(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('deepmerge')) :
typeof define === 'function' && define.amd ? define(['exports', 'deepmerge'], factory) :
(global = global || self, factory(global.VuexPersistence = {}, global.deepmerge));
}(this, (function (exports, deepmerge) { 'use strict';
deepmerge = deepmerge && deepmerge.hasOwnProperty('default') ? deepmerge['default'] : deepmerge;
/**
* Created by championswimmer on 22/07/17.
*/
// tslint:disable: variable-name
var SimplePromiseQueue = /** @class */ (function () {
function SimplePromiseQueue() {
this._queue = [];
this._flushing = false;
}
SimplePromiseQueue.prototype.enqueue = function (promise) {
this._queue.push(promise);
if (!this._flushing) {
return this.flushQueue();
}
return Promise.resolve();
};
SimplePromiseQueue.prototype.flushQueue = function () {
var _this = this;
this._flushing = true;
var chain = function () {
var nextTask = _this._queue.shift();
if (nextTask) {
return nextTask.then(chain);
}
else {
_this._flushing = false;
}
};
return Promise.resolve(chain());
};
return SimplePromiseQueue;
}());
var options = {
replaceArrays: {
arrayMerge: function (destinationArray, sourceArray, options) { return sourceArray; }
},
concatArrays: {
arrayMerge: function (target, source, options) { return target.concat.apply(target, source); }
}
};
function merge(into, from, mergeOption) {
return deepmerge(into, from, options[mergeOption]);
}
var FlattedJSON = JSON;
/**
* A class that implements the vuex persistence.
* @type S type of the 'state' inside the store (default: any)
*/
var VuexPersistence = /** @class */ (function () {
/**
* Create a {@link VuexPersistence} object.
* Use the plugin
function of this class as a
* Vuex plugin.
* @param {PersistOptions} options
*/
function VuexPersistence(options) {
var _this = this;
// tslint:disable-next-line:variable-name
this._mutex = new SimplePromiseQueue();
/**
* Creates a subscriber on the store. automatically is used
* when this is used a vuex plugin. Not for manual usage.
* @param store
*/
this.subscriber = function (store) {
return function (handler) { return store.subscribe(handler); };
};
if (typeof options === 'undefined')
options = {};
this.key = ((options.key != null) ? options.key : 'vuex');
this.subscribed = false;
this.supportCircular = options.supportCircular || false;
if (this.supportCircular) {
FlattedJSON = require('flatted');
}
this.mergeOption = options.mergeOption || 'replaceArrays';
var localStorageLitmus = true;
try {
window.localStorage.getItem('');
}
catch (err) {
localStorageLitmus = false;
}
/**
* 1. First, prefer storage sent in optinos
* 2. Otherwise, use window.localStorage if available
* 3. Finally, try to use MockStorage
* 4. None of above? Well we gotta fail.
*/
if (options.storage) {
this.storage = options.storage;
}
else if (localStorageLitmus) {
this.storage = window.localStorage;
}
else if (exports.MockStorage) {
this.storage = new exports.MockStorage();
}
else {
throw new Error("Neither 'window' is defined, nor 'MockStorage' is available");
}
/**
* How this works is -
* 1. If there is options.reducer function, we use that, if not;
* 2. We check options.modules;
* 1. If there is no options.modules array, we use entire state in reducer
* 2. Otherwise, we create a reducer that merges all those state modules that are
* defined in the options.modules[] array
* @type {((state: S) => {}) | ((state: S) => S) | ((state: any) => {})}
*/
this.reducer = ((options.reducer != null)
? options.reducer
: ((options.modules == null)
? (function (state) { return state; })
: (function (state) {
return options.modules.reduce(function (a, i) {
var _a;
return merge(a, (_a = {}, _a[i] = state[i], _a), _this.mergeOption);
}, { /* start empty accumulator*/});
})));
this.filter = options.filter || (function (mutation) { return true; });
this.strictMode = options.strictMode || false;
this.RESTORE_MUTATION = function RESTORE_MUTATION(state, savedState) {
var mergedState = merge(state, savedState || {}, this.mergeOption);
for (var _i = 0, _a = Object.keys(mergedState); _i < _a.length; _i++) {
var propertyName = _a[_i];
this._vm.$set(state, propertyName, mergedState[propertyName]);
}
};
this.asyncStorage = options.asyncStorage || false;
if (this.asyncStorage) {
/**
* Async {@link #VuexPersistence.restoreState} implementation
* @type {((key: string, storage?: Storage) =>
* (Promise | S)) | ((key: string, storage: AsyncStorage) => Promise)}
*/
this.restoreState = ((options.restoreState != null)
? options.restoreState
: (function (key, storage) {
return (storage).getItem(key)
.then(function (value) {
return typeof value === 'string' // If string, parse, or else, just return
? (_this.supportCircular
? FlattedJSON.parse(value || '{}')
: JSON.parse(value || '{}'))
: (value || {});
});
}));
/**
* Async {@link #VuexPersistence.saveState} implementation
* @type {((key: string, state: {}, storage?: Storage) =>
* (Promise | void)) | ((key: string, state: {}, storage?: Storage) => Promise)}
*/
this.saveState = ((options.saveState != null)
? options.saveState
: (function (key, state, storage) {
return (storage).setItem(key, // Second argument is state _object_ if asyc storage, stringified otherwise
// do not stringify the state if the storage type is async
(_this.asyncStorage
? merge({}, state || {}, _this.mergeOption)
: (_this.supportCircular
? FlattedJSON.stringify(state)
: JSON.stringify(state))));
}));
/**
* Async version of plugin
* @param {Store} store
*/
this.plugin = function (store) {
/**
* For async stores, we're capturing the Promise returned
* by the `restoreState()` function in a `restored` property
* on the store itself. This would allow app developers to
* determine when and if the store's state has indeed been
* refreshed. This approach was suggested by GitHub user @hotdogee.
* See https://github.com/championswimmer/vuex-persist/pull/118#issuecomment-500914963
* @since 2.1.0
*/
store.restored = (_this.restoreState(_this.key, _this.storage)).then(function (savedState) {
/**
* If in strict mode, do only via mutation
*/
if (_this.strictMode) {
store.commit('RESTORE_MUTATION', savedState);
}
else {
store.replaceState(merge(store.state, savedState || {}, _this.mergeOption));
}
_this.subscriber(store)(function (mutation, state) {
if (_this.filter(mutation)) {
_this._mutex.enqueue(_this.saveState(_this.key, _this.reducer(state), _this.storage));
}
});
_this.subscribed = true;
});
};
}
else {
/**
* Sync {@link #VuexPersistence.restoreState} implementation
* @type {((key: string, storage?: Storage) =>
* (Promise | S)) | ((key: string, storage: Storage) => (any | string | {}))}
*/
this.restoreState = ((options.restoreState != null)
? options.restoreState
: (function (key, storage) {
var value = (storage).getItem(key);
if (typeof value === 'string') { // If string, parse, or else, just return
return (_this.supportCircular
? FlattedJSON.parse(value || '{}')
: JSON.parse(value || '{}'));
}
else {
return (value || {});
}
}));
/**
* Sync {@link #VuexPersistence.saveState} implementation
* @type {((key: string, state: {}, storage?: Storage) =>
* (Promise | void)) | ((key: string, state: {}, storage?: Storage) => Promise)}
*/
this.saveState = ((options.saveState != null)
? options.saveState
: (function (key, state, storage) {
return (storage).setItem(key, // Second argument is state _object_ if localforage, stringified otherwise
(_this.supportCircular
? FlattedJSON.stringify(state)
: JSON.stringify(state)));
}));
/**
* Sync version of plugin
* @param {Store} store
*/
this.plugin = function (store) {
var savedState = _this.restoreState(_this.key, _this.storage);
if (_this.strictMode) {
store.commit('RESTORE_MUTATION', savedState);
}
else {
store.replaceState(merge(store.state, savedState || {}, _this.mergeOption));
}
_this.subscriber(store)(function (mutation, state) {
if (_this.filter(mutation)) {
_this.saveState(_this.key, _this.reducer(state), _this.storage);
}
});
_this.subscribed = true;
};
}
}
return VuexPersistence;
}());
exports.VuexPersistence = VuexPersistence;
exports.default = VuexPersistence;
Object.defineProperty(exports, '__esModule', { value: true });
})));
//# sourceMappingURL=index.js.map