UNPKG

28.3 kBJavaScriptView Raw
1/**
2 * vuex v4.0.0-alpha.1
3 * (c) 2020 Evan You
4 * @license MIT
5 */
6import { inject, watch, computed, reactive } from 'vue';
7
8const storeKey = 'store';
9
10function useStore (key = null) {
11 return inject(key !== null ? key : storeKey)
12}
13
14function applyMixin (app, store, injectKey) {
15 app.provide(injectKey || storeKey, store);
16
17 // TODO: Refactor this to use `provide/inject`. It's currently
18 // not possible because Vue 3 doesn't work with `$` prefixed
19 // `provide/inject` at the moment.
20 app.mixin({
21 beforeCreate () {
22 if (!this.parent) {
23 this.$store = typeof store === 'function' ? store() : store;
24 } else {
25 this.$store = this.parent.$options.$store;
26 }
27 }
28 });
29}
30
31const target = typeof window !== 'undefined'
32 ? window
33 : typeof global !== 'undefined'
34 ? global
35 : {};
36const devtoolHook = target.__VUE_DEVTOOLS_GLOBAL_HOOK__;
37
38function devtoolPlugin (store) {
39 if (!devtoolHook) return
40
41 store._devtoolHook = devtoolHook;
42
43 devtoolHook.emit('vuex:init', store);
44
45 devtoolHook.on('vuex:travel-to-state', targetState => {
46 store.replaceState(targetState);
47 });
48
49 store.subscribe((mutation, state) => {
50 devtoolHook.emit('vuex:mutation', mutation, state);
51 });
52}
53
54/**
55 * Get the first item that pass the test
56 * by second argument function
57 *
58 * @param {Array} list
59 * @param {Function} f
60 * @return {*}
61 */
62
63/**
64 * forEach for object
65 */
66function forEachValue (obj, fn) {
67 Object.keys(obj).forEach(key => fn(obj[key], key));
68}
69
70function isObject (obj) {
71 return obj !== null && typeof obj === 'object'
72}
73
74function isPromise (val) {
75 return val && typeof val.then === 'function'
76}
77
78function assert (condition, msg) {
79 if (!condition) throw new Error(`[vuex] ${msg}`)
80}
81
82function partial (fn, arg) {
83 return function () {
84 return fn(arg)
85 }
86}
87
88// Base data struct for store's module, package with some attribute and method
89class Module {
90 constructor (rawModule, runtime) {
91 this.runtime = runtime;
92 // Store some children item
93 this._children = Object.create(null);
94 // Store the origin module object which passed by programmer
95 this._rawModule = rawModule;
96 const rawState = rawModule.state;
97
98 // Store the origin module's state
99 this.state = (typeof rawState === 'function' ? rawState() : rawState) || {};
100 }
101
102 get namespaced () {
103 return !!this._rawModule.namespaced
104 }
105
106 addChild (key, module) {
107 this._children[key] = module;
108 }
109
110 removeChild (key) {
111 delete this._children[key];
112 }
113
114 getChild (key) {
115 return this._children[key]
116 }
117
118 update (rawModule) {
119 this._rawModule.namespaced = rawModule.namespaced;
120 if (rawModule.actions) {
121 this._rawModule.actions = rawModule.actions;
122 }
123 if (rawModule.mutations) {
124 this._rawModule.mutations = rawModule.mutations;
125 }
126 if (rawModule.getters) {
127 this._rawModule.getters = rawModule.getters;
128 }
129 }
130
131 forEachChild (fn) {
132 forEachValue(this._children, fn);
133 }
134
135 forEachGetter (fn) {
136 if (this._rawModule.getters) {
137 forEachValue(this._rawModule.getters, fn);
138 }
139 }
140
141 forEachAction (fn) {
142 if (this._rawModule.actions) {
143 forEachValue(this._rawModule.actions, fn);
144 }
145 }
146
147 forEachMutation (fn) {
148 if (this._rawModule.mutations) {
149 forEachValue(this._rawModule.mutations, fn);
150 }
151 }
152}
153
154class ModuleCollection {
155 constructor (rawRootModule) {
156 // register root module (Vuex.Store options)
157 this.register([], rawRootModule, false);
158 }
159
160 get (path) {
161 return path.reduce((module, key) => {
162 return module.getChild(key)
163 }, this.root)
164 }
165
166 getNamespace (path) {
167 let module = this.root;
168 return path.reduce((namespace, key) => {
169 module = module.getChild(key);
170 return namespace + (module.namespaced ? key + '/' : '')
171 }, '')
172 }
173
174 update (rawRootModule) {
175 update([], this.root, rawRootModule);
176 }
177
178 register (path, rawModule, runtime = true) {
179 {
180 assertRawModule(path, rawModule);
181 }
182
183 const newModule = new Module(rawModule, runtime);
184 if (path.length === 0) {
185 this.root = newModule;
186 } else {
187 const parent = this.get(path.slice(0, -1));
188 parent.addChild(path[path.length - 1], newModule);
189 }
190
191 // register nested modules
192 if (rawModule.modules) {
193 forEachValue(rawModule.modules, (rawChildModule, key) => {
194 this.register(path.concat(key), rawChildModule, runtime);
195 });
196 }
197 }
198
199 unregister (path) {
200 const parent = this.get(path.slice(0, -1));
201 const key = path[path.length - 1];
202 if (!parent.getChild(key).runtime) return
203
204 parent.removeChild(key);
205 }
206}
207
208function update (path, targetModule, newModule) {
209 {
210 assertRawModule(path, newModule);
211 }
212
213 // update target module
214 targetModule.update(newModule);
215
216 // update nested modules
217 if (newModule.modules) {
218 for (const key in newModule.modules) {
219 if (!targetModule.getChild(key)) {
220 {
221 console.warn(
222 `[vuex] trying to add a new module '${key}' on hot reloading, ` +
223 'manual reload is needed'
224 );
225 }
226 return
227 }
228 update(
229 path.concat(key),
230 targetModule.getChild(key),
231 newModule.modules[key]
232 );
233 }
234 }
235}
236
237const functionAssert = {
238 assert: value => typeof value === 'function',
239 expected: 'function'
240};
241
242const objectAssert = {
243 assert: value => typeof value === 'function' ||
244 (typeof value === 'object' && typeof value.handler === 'function'),
245 expected: 'function or object with "handler" function'
246};
247
248const assertTypes = {
249 getters: functionAssert,
250 mutations: functionAssert,
251 actions: objectAssert
252};
253
254function assertRawModule (path, rawModule) {
255 Object.keys(assertTypes).forEach(key => {
256 if (!rawModule[key]) return
257
258 const assertOptions = assertTypes[key];
259
260 forEachValue(rawModule[key], (value, type) => {
261 assert(
262 assertOptions.assert(value),
263 makeAssertionMessage(path, key, type, value, assertOptions.expected)
264 );
265 });
266 });
267}
268
269function makeAssertionMessage (path, key, type, value, expected) {
270 let buf = `${key} should be ${expected} but "${key}.${type}"`;
271 if (path.length > 0) {
272 buf += ` in module "${path.join('.')}"`;
273 }
274 buf += ` is ${JSON.stringify(value)}.`;
275 return buf
276}
277
278// let Vue // bind on install
279
280function createStore (options) {
281 return new Store(options)
282}
283
284class Store {
285 constructor (options = {}) {
286 // TODO: Bring back this one if needed.
287 //
288 // Auto install if it is not done yet and `window` has `Vue`.
289 // To allow users to avoid auto-installation in some cases,
290 // this code should be placed here. See #731
291 // if (!Vue && typeof window !== 'undefined' && window.Vue) {
292 // install(window.Vue)
293 // }
294
295 {
296 // TODO: Maybe we can remove this depending on the new implementation.
297 // assert(Vue, `must call Vue.use(Vuex) before creating a store instance.`)
298 assert(typeof Promise !== 'undefined', `vuex requires a Promise polyfill in this browser.`);
299 assert(this instanceof Store, `store must be called with the new operator.`);
300 }
301
302 const {
303 plugins = [],
304 strict = false
305 } = options;
306
307 // store internal state
308 this._committing = false;
309 this._actions = Object.create(null);
310 this._actionSubscribers = [];
311 this._mutations = Object.create(null);
312 this._wrappedGetters = Object.create(null);
313 this._modules = new ModuleCollection(options);
314 this._modulesNamespaceMap = Object.create(null);
315 this._subscribers = [];
316 this._makeLocalGettersCache = Object.create(null);
317
318 // bind commit and dispatch to self
319 const store = this;
320 const { dispatch, commit } = this;
321 this.dispatch = function boundDispatch (type, payload) {
322 return dispatch.call(store, type, payload)
323 };
324 this.commit = function boundCommit (type, payload, options) {
325 return commit.call(store, type, payload, options)
326 };
327
328 // strict mode
329 this.strict = strict;
330
331 const state = this._modules.root.state;
332
333 // init root module.
334 // this also recursively registers all sub-modules
335 // and collects all module getters inside this._wrappedGetters
336 installModule(this, state, [], this._modules.root);
337
338 // initialize the store vm, which is responsible for the reactivity
339 // (also registers _wrappedGetters as computed properties)
340 resetStoreVM(this, state);
341
342 // apply plugins
343 plugins.forEach(plugin => plugin(this));
344
345 const useDevtools = options.devtools !== undefined ? options.devtools : /* Vue.config.devtools */ true;
346 if (useDevtools) {
347 devtoolPlugin(this);
348 }
349 }
350
351 install (app, injectKey) {
352 // TODO: Removing double install check for now. Maybe we can bring this
353 // feature back again if needed.
354 //
355 // if (Vue && _Vue === Vue) {
356 // if ("development" !== 'production') {
357 // console.error(
358 // '[vuex] already installed. Vue.use(Vuex) should be called only once.'
359 // )
360 // }
361 // return
362 // }
363 // Vue = _Vue
364
365 applyMixin(app, this, injectKey);
366 }
367
368 get state () {
369 return this._vm._data.$$state
370 }
371
372 set state (v) {
373 {
374 assert(false, `use store.replaceState() to explicit replace store state.`);
375 }
376 }
377
378 commit (_type, _payload, _options) {
379 // check object-style commit
380 const {
381 type,
382 payload,
383 options
384 } = unifyObjectStyle(_type, _payload, _options);
385
386 const mutation = { type, payload };
387 const entry = this._mutations[type];
388 if (!entry) {
389 {
390 console.error(`[vuex] unknown mutation type: ${type}`);
391 }
392 return
393 }
394 this._withCommit(() => {
395 entry.forEach(function commitIterator (handler) {
396 handler(payload);
397 });
398 });
399
400 this._subscribers
401 .slice() // shallow copy to prevent iterator invalidation if subscriber synchronously calls unsubscribe
402 .forEach(sub => sub(mutation, this.state));
403
404 if (
405 options && options.silent
406 ) {
407 console.warn(
408 `[vuex] mutation type: ${type}. Silent option has been removed. ` +
409 'Use the filter functionality in the vue-devtools'
410 );
411 }
412 }
413
414 dispatch (_type, _payload) {
415 // check object-style dispatch
416 const {
417 type,
418 payload
419 } = unifyObjectStyle(_type, _payload);
420
421 const action = { type, payload };
422 const entry = this._actions[type];
423 if (!entry) {
424 {
425 console.error(`[vuex] unknown action type: ${type}`);
426 }
427 return
428 }
429
430 try {
431 this._actionSubscribers
432 .slice() // shallow copy to prevent iterator invalidation if subscriber synchronously calls unsubscribe
433 .filter(sub => sub.before)
434 .forEach(sub => sub.before(action, this.state));
435 } catch (e) {
436 {
437 console.warn(`[vuex] error in before action subscribers: `);
438 console.error(e);
439 }
440 }
441
442 const result = entry.length > 1
443 ? Promise.all(entry.map(handler => handler(payload)))
444 : entry[0](payload);
445
446 return result.then(res => {
447 try {
448 this._actionSubscribers
449 .filter(sub => sub.after)
450 .forEach(sub => sub.after(action, this.state));
451 } catch (e) {
452 {
453 console.warn(`[vuex] error in after action subscribers: `);
454 console.error(e);
455 }
456 }
457 return res
458 })
459 }
460
461 subscribe (fn) {
462 return genericSubscribe(fn, this._subscribers)
463 }
464
465 subscribeAction (fn) {
466 const subs = typeof fn === 'function' ? { before: fn } : fn;
467 return genericSubscribe(subs, this._actionSubscribers)
468 }
469
470 watch (getter, cb, options) {
471 {
472 assert(typeof getter === 'function', `store.watch only accepts a function.`);
473 }
474 return watch(() => getter(this.state, this.getters), cb, Object.assign({}, options))
475 }
476
477 replaceState (state) {
478 this._withCommit(() => {
479 this._vm._data.$$state = state;
480 });
481 }
482
483 registerModule (path, rawModule, options = {}) {
484 if (typeof path === 'string') path = [path];
485
486 {
487 assert(Array.isArray(path), `module path must be a string or an Array.`);
488 assert(path.length > 0, 'cannot register the root module by using registerModule.');
489 }
490
491 this._modules.register(path, rawModule);
492 installModule(this, this.state, path, this._modules.get(path), options.preserveState);
493 // reset store to update getters...
494 resetStoreVM(this, this.state);
495 }
496
497 unregisterModule (path) {
498 if (typeof path === 'string') path = [path];
499
500 {
501 assert(Array.isArray(path), `module path must be a string or an Array.`);
502 }
503
504 this._modules.unregister(path);
505 this._withCommit(() => {
506 const parentState = getNestedState(this.state, path.slice(0, -1));
507 delete parentState[path[path.length - 1]];
508 });
509 resetStore(this);
510 }
511
512 hotUpdate (newOptions) {
513 this._modules.update(newOptions);
514 resetStore(this, true);
515 }
516
517 _withCommit (fn) {
518 const committing = this._committing;
519 this._committing = true;
520 fn();
521 this._committing = committing;
522 }
523}
524
525function genericSubscribe (fn, subs) {
526 if (subs.indexOf(fn) < 0) {
527 subs.push(fn);
528 }
529 return () => {
530 const i = subs.indexOf(fn);
531 if (i > -1) {
532 subs.splice(i, 1);
533 }
534 }
535}
536
537function resetStore (store, hot) {
538 store._actions = Object.create(null);
539 store._mutations = Object.create(null);
540 store._wrappedGetters = Object.create(null);
541 store._modulesNamespaceMap = Object.create(null);
542 const state = store.state;
543 // init all modules
544 installModule(store, state, [], store._modules.root, true);
545 // reset vm
546 resetStoreVM(store, state, hot);
547}
548
549function resetStoreVM (store, state, hot) {
550 const oldVm = store._vm;
551
552 // bind store public getters
553 store.getters = {};
554 // reset local getters cache
555 store._makeLocalGettersCache = Object.create(null);
556 const wrappedGetters = store._wrappedGetters;
557 const computedObj = {};
558 forEachValue(wrappedGetters, (fn, key) => {
559 // TODO: Refactor following code and comment. We can simplify many things
560 // using computed function.
561 //
562 // use computed to leverage its lazy-caching mechanism
563 // direct inline function use will lead to closure preserving oldVm.
564 // using partial to return function with only arguments preserved in closure environment.
565 computedObj[key] = partial(fn, store);
566 Object.defineProperty(store.getters, key, {
567 get: () => computed(() => computedObj[key]()).value,
568 enumerable: true // for local getters
569 });
570 });
571
572 // TODO: Bring back this if it's still needed.
573 //
574 // use a Vue instance to store the state tree
575 // suppress warnings just in case the user has added
576 // some funky global mixins
577 // const silent = Vue.config.silent
578 // Vue.config.silent = true
579
580 // TODO: Refactor the code and remove this comment.
581 //
582 // New impl with reactive. Defining redundunt keys to make it as close as
583 // the old impl api.
584 store._vm = reactive({
585 _data: {
586 $$state: state
587 }
588 });
589
590 // TODO: Bring back maybe?
591 //
592 // Vue.config.silent = silent
593
594 // enable strict mode for new vm
595 if (store.strict) {
596 enableStrictMode(store);
597 }
598
599 if (oldVm) {
600 if (hot) {
601 // dispatch changes in all subscribed watchers
602 // to force getter re-evaluation for hot reloading.
603 store._withCommit(() => {
604 oldVm._data.$$state = null;
605 });
606 }
607 // TODO: I think we don't need this anymore since we're not using vm?
608 // Vue.nextTick(() => oldVm.$destroy())
609 }
610}
611
612function installModule (store, rootState, path, module, hot) {
613 const isRoot = !path.length;
614 const namespace = store._modules.getNamespace(path);
615
616 // register in namespace map
617 if (module.namespaced) {
618 if (store._modulesNamespaceMap[namespace] && "development" !== 'production') {
619 console.error(`[vuex] duplicate namespace ${namespace} for the namespaced module ${path.join('/')}`);
620 }
621 store._modulesNamespaceMap[namespace] = module;
622 }
623
624 // set state
625 if (!isRoot && !hot) {
626 const parentState = getNestedState(rootState, path.slice(0, -1));
627 const moduleName = path[path.length - 1];
628 store._withCommit(() => {
629 {
630 if (moduleName in parentState) {
631 console.warn(
632 `[vuex] state field "${moduleName}" was overridden by a module with the same name at "${path.join('.')}"`
633 );
634 }
635 }
636 parentState[moduleName] = module.state;
637 });
638 }
639
640 const local = module.context = makeLocalContext(store, namespace, path);
641
642 module.forEachMutation((mutation, key) => {
643 const namespacedType = namespace + key;
644 registerMutation(store, namespacedType, mutation, local);
645 });
646
647 module.forEachAction((action, key) => {
648 const type = action.root ? key : namespace + key;
649 const handler = action.handler || action;
650 registerAction(store, type, handler, local);
651 });
652
653 module.forEachGetter((getter, key) => {
654 const namespacedType = namespace + key;
655 registerGetter(store, namespacedType, getter, local);
656 });
657
658 module.forEachChild((child, key) => {
659 installModule(store, rootState, path.concat(key), child, hot);
660 });
661}
662
663/**
664 * make localized dispatch, commit, getters and state
665 * if there is no namespace, just use root ones
666 */
667function makeLocalContext (store, namespace, path) {
668 const noNamespace = namespace === '';
669
670 const local = {
671 dispatch: noNamespace ? store.dispatch : (_type, _payload, _options) => {
672 const args = unifyObjectStyle(_type, _payload, _options);
673 const { payload, options } = args;
674 let { type } = args;
675
676 if (!options || !options.root) {
677 type = namespace + type;
678 if (!store._actions[type]) {
679 console.error(`[vuex] unknown local action type: ${args.type}, global type: ${type}`);
680 return
681 }
682 }
683
684 return store.dispatch(type, payload)
685 },
686
687 commit: noNamespace ? store.commit : (_type, _payload, _options) => {
688 const args = unifyObjectStyle(_type, _payload, _options);
689 const { payload, options } = args;
690 let { type } = args;
691
692 if (!options || !options.root) {
693 type = namespace + type;
694 if (!store._mutations[type]) {
695 console.error(`[vuex] unknown local mutation type: ${args.type}, global type: ${type}`);
696 return
697 }
698 }
699
700 store.commit(type, payload, options);
701 }
702 };
703
704 // getters and state object must be gotten lazily
705 // because they will be changed by vm update
706 Object.defineProperties(local, {
707 getters: {
708 get: noNamespace
709 ? () => store.getters
710 : () => makeLocalGetters(store, namespace)
711 },
712 state: {
713 get: () => getNestedState(store.state, path)
714 }
715 });
716
717 return local
718}
719
720function makeLocalGetters (store, namespace) {
721 if (!store._makeLocalGettersCache[namespace]) {
722 const gettersProxy = {};
723 const splitPos = namespace.length;
724 Object.keys(store.getters).forEach(type => {
725 // skip if the target getter is not match this namespace
726 if (type.slice(0, splitPos) !== namespace) return
727
728 // extract local getter type
729 const localType = type.slice(splitPos);
730
731 // Add a port to the getters proxy.
732 // Define as getter property because
733 // we do not want to evaluate the getters in this time.
734 Object.defineProperty(gettersProxy, localType, {
735 get: () => store.getters[type],
736 enumerable: true
737 });
738 });
739 store._makeLocalGettersCache[namespace] = gettersProxy;
740 }
741
742 return store._makeLocalGettersCache[namespace]
743}
744
745function registerMutation (store, type, handler, local) {
746 const entry = store._mutations[type] || (store._mutations[type] = []);
747 entry.push(function wrappedMutationHandler (payload) {
748 handler.call(store, local.state, payload);
749 });
750}
751
752function registerAction (store, type, handler, local) {
753 const entry = store._actions[type] || (store._actions[type] = []);
754 entry.push(function wrappedActionHandler (payload) {
755 let res = handler.call(store, {
756 dispatch: local.dispatch,
757 commit: local.commit,
758 getters: local.getters,
759 state: local.state,
760 rootGetters: store.getters,
761 rootState: store.state
762 }, payload);
763 if (!isPromise(res)) {
764 res = Promise.resolve(res);
765 }
766 if (store._devtoolHook) {
767 return res.catch(err => {
768 store._devtoolHook.emit('vuex:error', err);
769 throw err
770 })
771 } else {
772 return res
773 }
774 });
775}
776
777function registerGetter (store, type, rawGetter, local) {
778 if (store._wrappedGetters[type]) {
779 {
780 console.error(`[vuex] duplicate getter key: ${type}`);
781 }
782 return
783 }
784 store._wrappedGetters[type] = function wrappedGetter (store) {
785 return rawGetter(
786 local.state, // local state
787 local.getters, // local getters
788 store.state, // root state
789 store.getters // root getters
790 )
791 };
792}
793
794function enableStrictMode (store) {
795 watch(() => store._vm._data.$$state, () => {
796 {
797 assert(store._committing, `do not mutate vuex store state outside mutation handlers.`);
798 }
799 }, { deep: true, flush: 'sync' });
800}
801
802function getNestedState (state, path) {
803 return path.reduce((state, key) => state[key], state)
804}
805
806function unifyObjectStyle (type, payload, options) {
807 if (isObject(type) && type.type) {
808 options = payload;
809 payload = type;
810 type = type.type;
811 }
812
813 {
814 assert(typeof type === 'string', `expects string as the type, but found ${typeof type}.`);
815 }
816
817 return { type, payload, options }
818}
819
820/**
821 * Reduce the code which written in Vue.js for getting the state.
822 * @param {String} [namespace] - Module's namespace
823 * @param {Object|Array} states # Object's item can be a function which accept state and getters for param, you can do something for state and getters in it.
824 * @param {Object}
825 */
826const mapState = normalizeNamespace((namespace, states) => {
827 const res = {};
828 if (!isValidMap(states)) {
829 console.error('[vuex] mapState: mapper parameter must be either an Array or an Object');
830 }
831 normalizeMap(states).forEach(({ key, val }) => {
832 res[key] = function mappedState () {
833 let state = this.$store.state;
834 let getters = this.$store.getters;
835 if (namespace) {
836 const module = getModuleByNamespace(this.$store, 'mapState', namespace);
837 if (!module) {
838 return
839 }
840 state = module.context.state;
841 getters = module.context.getters;
842 }
843 return typeof val === 'function'
844 ? val.call(this, state, getters)
845 : state[val]
846 };
847 // mark vuex getter for devtools
848 res[key].vuex = true;
849 });
850 return res
851});
852
853/**
854 * Reduce the code which written in Vue.js for committing the mutation
855 * @param {String} [namespace] - Module's namespace
856 * @param {Object|Array} mutations # Object's item can be a function which accept `commit` function as the first param, it can accept anthor params. You can commit mutation and do any other things in this function. specially, You need to pass anthor params from the mapped function.
857 * @return {Object}
858 */
859const mapMutations = normalizeNamespace((namespace, mutations) => {
860 const res = {};
861 if (!isValidMap(mutations)) {
862 console.error('[vuex] mapMutations: mapper parameter must be either an Array or an Object');
863 }
864 normalizeMap(mutations).forEach(({ key, val }) => {
865 res[key] = function mappedMutation (...args) {
866 // Get the commit method from store
867 let commit = this.$store.commit;
868 if (namespace) {
869 const module = getModuleByNamespace(this.$store, 'mapMutations', namespace);
870 if (!module) {
871 return
872 }
873 commit = module.context.commit;
874 }
875 return typeof val === 'function'
876 ? val.apply(this, [commit].concat(args))
877 : commit.apply(this.$store, [val].concat(args))
878 };
879 });
880 return res
881});
882
883/**
884 * Reduce the code which written in Vue.js for getting the getters
885 * @param {String} [namespace] - Module's namespace
886 * @param {Object|Array} getters
887 * @return {Object}
888 */
889const mapGetters = normalizeNamespace((namespace, getters) => {
890 const res = {};
891 if (!isValidMap(getters)) {
892 console.error('[vuex] mapGetters: mapper parameter must be either an Array or an Object');
893 }
894 normalizeMap(getters).forEach(({ key, val }) => {
895 // The namespace has been mutated by normalizeNamespace
896 val = namespace + val;
897 res[key] = function mappedGetter () {
898 if (namespace && !getModuleByNamespace(this.$store, 'mapGetters', namespace)) {
899 return
900 }
901 if (!(val in this.$store.getters)) {
902 console.error(`[vuex] unknown getter: ${val}`);
903 return
904 }
905 return this.$store.getters[val]
906 };
907 // mark vuex getter for devtools
908 res[key].vuex = true;
909 });
910 return res
911});
912
913/**
914 * Reduce the code which written in Vue.js for dispatch the action
915 * @param {String} [namespace] - Module's namespace
916 * @param {Object|Array} actions # Object's item can be a function which accept `dispatch` function as the first param, it can accept anthor params. You can dispatch action and do any other things in this function. specially, You need to pass anthor params from the mapped function.
917 * @return {Object}
918 */
919const mapActions = normalizeNamespace((namespace, actions) => {
920 const res = {};
921 if (!isValidMap(actions)) {
922 console.error('[vuex] mapActions: mapper parameter must be either an Array or an Object');
923 }
924 normalizeMap(actions).forEach(({ key, val }) => {
925 res[key] = function mappedAction (...args) {
926 // get dispatch function from store
927 let dispatch = this.$store.dispatch;
928 if (namespace) {
929 const module = getModuleByNamespace(this.$store, 'mapActions', namespace);
930 if (!module) {
931 return
932 }
933 dispatch = module.context.dispatch;
934 }
935 return typeof val === 'function'
936 ? val.apply(this, [dispatch].concat(args))
937 : dispatch.apply(this.$store, [val].concat(args))
938 };
939 });
940 return res
941});
942
943/**
944 * Rebinding namespace param for mapXXX function in special scoped, and return them by simple object
945 * @param {String} namespace
946 * @return {Object}
947 */
948const createNamespacedHelpers = (namespace) => ({
949 mapState: mapState.bind(null, namespace),
950 mapGetters: mapGetters.bind(null, namespace),
951 mapMutations: mapMutations.bind(null, namespace),
952 mapActions: mapActions.bind(null, namespace)
953});
954
955/**
956 * Normalize the map
957 * normalizeMap([1, 2, 3]) => [ { key: 1, val: 1 }, { key: 2, val: 2 }, { key: 3, val: 3 } ]
958 * normalizeMap({a: 1, b: 2, c: 3}) => [ { key: 'a', val: 1 }, { key: 'b', val: 2 }, { key: 'c', val: 3 } ]
959 * @param {Array|Object} map
960 * @return {Object}
961 */
962function normalizeMap (map) {
963 if (!isValidMap(map)) {
964 return []
965 }
966 return Array.isArray(map)
967 ? map.map(key => ({ key, val: key }))
968 : Object.keys(map).map(key => ({ key, val: map[key] }))
969}
970
971/**
972 * Validate whether given map is valid or not
973 * @param {*} map
974 * @return {Boolean}
975 */
976function isValidMap (map) {
977 return Array.isArray(map) || isObject(map)
978}
979
980/**
981 * Return a function expect two param contains namespace and map. it will normalize the namespace and then the param's function will handle the new namespace and the map.
982 * @param {Function} fn
983 * @return {Function}
984 */
985function normalizeNamespace (fn) {
986 return (namespace, map) => {
987 if (typeof namespace !== 'string') {
988 map = namespace;
989 namespace = '';
990 } else if (namespace.charAt(namespace.length - 1) !== '/') {
991 namespace += '/';
992 }
993 return fn(namespace, map)
994 }
995}
996
997/**
998 * Search a special module from store by namespace. if module not exist, print error message.
999 * @param {Object} store
1000 * @param {String} helper
1001 * @param {String} namespace
1002 * @return {Object}
1003 */
1004function getModuleByNamespace (store, helper, namespace) {
1005 const module = store._modulesNamespaceMap[namespace];
1006 if (!module) {
1007 console.error(`[vuex] module namespace not found in ${helper}(): ${namespace}`);
1008 }
1009 return module
1010}
1011
1012var index_esm = {
1013 version: '4.0.0-alpha.1',
1014 createStore,
1015 Store,
1016 useStore,
1017 mapState,
1018 mapMutations,
1019 mapGetters,
1020 mapActions,
1021 createNamespacedHelpers
1022};
1023
1024export default index_esm;
1025export { createStore, Store, useStore, mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers };