index.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('lodash')) :
  3. typeof define === 'function' && define.amd ? define(['exports', 'lodash'], factory) :
  4. (global = global || self, factory(global.VuexPersistence = {}, global._));
  5. }(this, (function (exports, lodash) { 'use strict';
  6. /**
  7. * Created by championswimmer on 22/07/17.
  8. */
  9. // tslint:disable: variable-name
  10. var SimplePromiseQueue = /** @class */ (function () {
  11. function SimplePromiseQueue() {
  12. this._queue = [];
  13. this._flushing = false;
  14. }
  15. SimplePromiseQueue.prototype.enqueue = function (promise) {
  16. this._queue.push(promise);
  17. if (!this._flushing) {
  18. return this.flushQueue();
  19. }
  20. return Promise.resolve();
  21. };
  22. SimplePromiseQueue.prototype.flushQueue = function () {
  23. var _this = this;
  24. this._flushing = true;
  25. var chain = function () {
  26. var nextTask = _this._queue.shift();
  27. if (nextTask) {
  28. return nextTask.then(chain);
  29. }
  30. else {
  31. _this._flushing = false;
  32. }
  33. };
  34. return Promise.resolve(chain());
  35. };
  36. return SimplePromiseQueue;
  37. }());
  38. function merge(into, from) {
  39. return lodash.merge({}, into, from);
  40. }
  41. var FlattedJSON = JSON;
  42. /**
  43. * A class that implements the vuex persistence.
  44. * @type S type of the 'state' inside the store (default: any)
  45. */
  46. var VuexPersistence = /** @class */ (function () {
  47. /**
  48. * Create a {@link VuexPersistence} object.
  49. * Use the <code>plugin</code> function of this class as a
  50. * Vuex plugin.
  51. * @param {PersistOptions} options
  52. */
  53. function VuexPersistence(options) {
  54. var _this = this;
  55. // tslint:disable-next-line:variable-name
  56. this._mutex = new SimplePromiseQueue();
  57. /**
  58. * Creates a subscriber on the store. automatically is used
  59. * when this is used a vuex plugin. Not for manual usage.
  60. * @param store
  61. */
  62. this.subscriber = function (store) {
  63. return function (handler) { return store.subscribe(handler); };
  64. };
  65. if (typeof options === 'undefined')
  66. options = {};
  67. this.key = ((options.key != null) ? options.key : 'vuex');
  68. this.subscribed = false;
  69. this.supportCircular = options.supportCircular || false;
  70. if (this.supportCircular) {
  71. FlattedJSON = require('flatted');
  72. }
  73. var localStorageLitmus = true;
  74. try {
  75. window.localStorage.getItem('');
  76. }
  77. catch (err) {
  78. localStorageLitmus = false;
  79. }
  80. this.storage = options.storage || localStorageLitmus && window.localStorage || exports.MockStorage && new exports.MockStorage();
  81. /**
  82. * How this works is -
  83. * 1. If there is options.reducer function, we use that, if not;
  84. * 2. We check options.modules;
  85. * 1. If there is no options.modules array, we use entire state in reducer
  86. * 2. Otherwise, we create a reducer that merges all those state modules that are
  87. * defined in the options.modules[] array
  88. * @type {((state: S) => {}) | ((state: S) => S) | ((state: any) => {})}
  89. */
  90. this.reducer = ((options.reducer != null)
  91. ? options.reducer
  92. : ((options.modules == null)
  93. ? (function (state) { return state; })
  94. : (function (state) {
  95. return options.modules.reduce(function (a, i) {
  96. var _a;
  97. return merge(a, (_a = {}, _a[i] = state[i], _a));
  98. }, { /* start empty accumulator*/});
  99. })));
  100. this.filter = options.filter || (function (mutation) { return true; });
  101. this.strictMode = options.strictMode || false;
  102. this.RESTORE_MUTATION = function RESTORE_MUTATION(state, savedState) {
  103. var mergedState = merge(state, savedState || {});
  104. for (var _i = 0, _a = Object.keys(mergedState); _i < _a.length; _i++) {
  105. var propertyName = _a[_i];
  106. this._vm.$set(state, propertyName, mergedState[propertyName]);
  107. }
  108. };
  109. this.asyncStorage = options.asyncStorage || false;
  110. if (this.asyncStorage) {
  111. /**
  112. * Async {@link #VuexPersistence.restoreState} implementation
  113. * @type {((key: string, storage?: Storage) =>
  114. * (Promise<S> | S)) | ((key: string, storage: AsyncStorage) => Promise<any>)}
  115. */
  116. this.restoreState = ((options.restoreState != null)
  117. ? options.restoreState
  118. : (function (key, storage) {
  119. return (storage).getItem(key)
  120. .then(function (value) {
  121. return typeof value === 'string' // If string, parse, or else, just return
  122. ? (_this.supportCircular
  123. ? FlattedJSON.parse(value || '{}')
  124. : JSON.parse(value || '{}'))
  125. : (value || {});
  126. });
  127. }));
  128. /**
  129. * Async {@link #VuexPersistence.saveState} implementation
  130. * @type {((key: string, state: {}, storage?: Storage) =>
  131. * (Promise<void> | void)) | ((key: string, state: {}, storage?: Storage) => Promise<void>)}
  132. */
  133. this.saveState = ((options.saveState != null)
  134. ? options.saveState
  135. : (function (key, state, storage) {
  136. return (storage).setItem(key, // Second argument is state _object_ if asyc storage, stringified otherwise
  137. // do not stringify the state if the storage type is async
  138. (_this.asyncStorage
  139. ? merge({}, state || {})
  140. : (_this.supportCircular
  141. ? FlattedJSON.stringify(state)
  142. : JSON.stringify(state))));
  143. }));
  144. /**
  145. * Async version of plugin
  146. * @param {Store<S>} store
  147. */
  148. this.plugin = function (store) {
  149. /**
  150. * For async stores, we're capturing the Promise returned
  151. * by the `restoreState()` function in a `restored` property
  152. * on the store itself. This would allow app developers to
  153. * determine when and if the store's state has indeed been
  154. * refreshed. This approach was suggested by GitHub user @hotdogee.
  155. * See https://github.com/championswimmer/vuex-persist/pull/118#issuecomment-500914963
  156. * @since 2.1.0
  157. */
  158. store.restored = (_this.restoreState(_this.key, _this.storage)).then(function (savedState) {
  159. /**
  160. * If in strict mode, do only via mutation
  161. */
  162. if (_this.strictMode) {
  163. store.commit('RESTORE_MUTATION', savedState);
  164. }
  165. else {
  166. store.replaceState(merge(store.state, savedState || {}));
  167. }
  168. _this.subscriber(store)(function (mutation, state) {
  169. if (_this.filter(mutation)) {
  170. _this._mutex.enqueue(_this.saveState(_this.key, _this.reducer(state), _this.storage));
  171. }
  172. });
  173. _this.subscribed = true;
  174. });
  175. };
  176. }
  177. else {
  178. /**
  179. * Sync {@link #VuexPersistence.restoreState} implementation
  180. * @type {((key: string, storage?: Storage) =>
  181. * (Promise<S> | S)) | ((key: string, storage: Storage) => (any | string | {}))}
  182. */
  183. this.restoreState = ((options.restoreState != null)
  184. ? options.restoreState
  185. : (function (key, storage) {
  186. var value = (storage).getItem(key);
  187. if (typeof value === 'string') { // If string, parse, or else, just return
  188. return (_this.supportCircular
  189. ? FlattedJSON.parse(value || '{}')
  190. : JSON.parse(value || '{}'));
  191. }
  192. else {
  193. return (value || {});
  194. }
  195. }));
  196. /**
  197. * Sync {@link #VuexPersistence.saveState} implementation
  198. * @type {((key: string, state: {}, storage?: Storage) =>
  199. * (Promise<void> | void)) | ((key: string, state: {}, storage?: Storage) => Promise<void>)}
  200. */
  201. this.saveState = ((options.saveState != null)
  202. ? options.saveState
  203. : (function (key, state, storage) {
  204. return (storage).setItem(key, // Second argument is state _object_ if localforage, stringified otherwise
  205. (_this.supportCircular
  206. ? FlattedJSON.stringify(state)
  207. : JSON.stringify(state)));
  208. }));
  209. /**
  210. * Sync version of plugin
  211. * @param {Store<S>} store
  212. */
  213. this.plugin = function (store) {
  214. var savedState = _this.restoreState(_this.key, _this.storage);
  215. if (_this.strictMode) {
  216. store.commit('RESTORE_MUTATION', savedState);
  217. }
  218. else {
  219. store.replaceState(merge(store.state, savedState || {}));
  220. }
  221. _this.subscriber(store)(function (mutation, state) {
  222. if (_this.filter(mutation)) {
  223. _this.saveState(_this.key, _this.reducer(state), _this.storage);
  224. }
  225. });
  226. _this.subscribed = true;
  227. };
  228. }
  229. }
  230. return VuexPersistence;
  231. }());
  232. exports.VuexPersistence = VuexPersistence;
  233. exports.default = VuexPersistence;
  234. Object.defineProperty(exports, '__esModule', { value: true });
  235. })));
  236. //# sourceMappingURL=index.js.map