UNPKG

mmlpx

Version:

mobx model layer paradigm

173 lines (160 loc) 6.08 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _pull2 = require('lodash/pull'); var _pull3 = _interopRequireDefault(_pull2); var _mergeWith2 = require('lodash/mergeWith'); var _mergeWith3 = _interopRequireDefault(_mergeWith2); exports.applySnapshot = applySnapshot; exports.patchSnapshot = patchSnapshot; exports.getSnapshot = getSnapshot; exports.onSnapshot = onSnapshot; var _mobx = require('mobx'); var _instantiate = require('../core/dependency-inject/instantiate'); var _types = require('../utils/types'); var _genReactiveInjector = require('./genReactiveInjector'); var _genReactiveInjector2 = _interopRequireDefault(_genReactiveInjector); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * @author Kuitos * @homepage https://github.com/kuitos/ * @since 2018-06-25 17:01 */ var SNAPSHOT_PHASE; (function (SNAPSHOT_PHASE) { SNAPSHOT_PHASE[SNAPSHOT_PHASE["PATCHING"] = 0] = "PATCHING"; SNAPSHOT_PHASE[SNAPSHOT_PHASE["DONE"] = 1] = "DONE"; })(SNAPSHOT_PHASE || (SNAPSHOT_PHASE = {})); var phase = SNAPSHOT_PHASE.DONE; /** * serialize and deep walk the models of injector to enable the dependencies tracking * @param model * @returns {Snapshot} serialization */ function walkAndSerialize(model) { // when model is an array, access the array length to enable tracking if ((0, _types.isArray)(model)) { return model.length ? model.map(function (value) { return walkAndSerialize(value); }) : []; } // when model is a map, access the map size to enable tracking if ((0, _types.isMap)(model)) { if (model.size) { var map_1 = {}; model.forEach(function (value, key) { map_1[key] = walkAndSerialize(value); }); return map_1; } return {}; } if ((0, _types.isObject)(model)) { return Object.keys(model).reduce(function (acc, stateName) { acc[stateName] = walkAndSerialize(model[stateName]); return acc; }, {}); } return model; } /** * hijack the mobx global state to run a processor after all reactions finished * @see https://github.com/mobxjs/mobx/blob/master/src/core/reaction.ts#L242 * :dark magic: * @param {() => void} processor */ function processAfterReactionsFinished(processor) { // compatible with mobx 3 var getGlobalState = _mobx._getGlobalState || /* istanbul ignore next */require('mobx').extras.getGlobalState; var globalState = getGlobalState(); var previousDescriptor = Object.getOwnPropertyDescriptor(globalState, 'isRunningReactions'); var prevValue = globalState.isRunningReactions; Object.defineProperty(globalState, 'isRunningReactions', { get: function () { return prevValue; }, set: function (v) { prevValue = v; if (v === false) { Object.defineProperty(globalState, 'isRunningReactions', previousDescriptor); processor(); } } }); } function applySnapshot(snapshot, injector) { if (injector === void 0) { injector = (0, _instantiate.getInjector)(); } if ((0, _types.isObject)(snapshot)) { patchSnapshot(snapshot, injector); } } function patchSnapshot(patcher, injector) { if (injector === void 0) { injector = (0, _instantiate.getInjector)(); } var currentModels = injector.dump(); phase = SNAPSHOT_PHASE.PATCHING; (0, _mobx.runInAction)(function () { // make a copy of patcher to avoid referencing the original patcher after merge var clonedPatcher = JSON.parse(JSON.stringify(patcher)); var mergedModels = (0, _mergeWith3.default)(currentModels, clonedPatcher, function (original, source) { // while source less than original, means the data list has items removed, so the overflowed data should be dropped if ((0, _types.isArray)(original)) { original.length = source.length; } // while the keys of source object less than original, means some properties should be removed in original after patch if ((0, _types.isObject)(original)) { _pull3.default.apply(void 0, [Object.keys(original)].concat(Object.keys(source))).forEach(function (key) { return delete original[key]; }); } if ((0, _types.isMap)(original)) { original.clear(); Object.keys(source).forEach(function (key) { original.set(key, source[key]); }); } }); injector.load(mergedModels); }); processAfterReactionsFinished(function () { return phase = SNAPSHOT_PHASE.DONE; }); } function getSnapshot(arg1, arg2) { if (typeof arg1 === 'string') { var snapshot = walkAndSerialize((arg2 || (0, _instantiate.getInjector)()).dump()); return snapshot[arg1]; } else { return walkAndSerialize((arg1 || (0, _instantiate.getInjector)()).dump()); } } function onSnapshot(arg1, arg2, arg3) { var snapshot; var onChange; var injector; if (typeof arg1 === 'string') { onChange = arg2; injector = (0, _genReactiveInjector2.default)(arg3 || (0, _instantiate.getInjector)()); snapshot = function () { return getSnapshot(arg1, injector); }; } else { onChange = arg1; injector = (0, _genReactiveInjector2.default)(arg2 || (0, _instantiate.getInjector)()); snapshot = function () { return getSnapshot(injector); }; } (0, _instantiate.setInjector)(injector); var disposer = (0, _mobx.reaction)(snapshot, function (changedSnapshot) { // only trigger snapshot listeners when snapshot processed if (phase === SNAPSHOT_PHASE.DONE) { onChange(changedSnapshot); } }, { equals: _mobx.comparer.structural }); return disposer; }