Comparing version 1.0.0-rc.2 to 2.0.0-rc.1
835
dist/vuex.js
/*! | ||
* Vuex v1.0.0-rc.2 | ||
* Vuex v2.0.0-rc.1 | ||
* (c) 2016 Evan You | ||
@@ -12,117 +12,2 @@ * Released under the MIT License. | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { | ||
return typeof obj; | ||
} : function (obj) { | ||
return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; | ||
}; | ||
var classCallCheck = function (instance, Constructor) { | ||
if (!(instance instanceof Constructor)) { | ||
throw new TypeError("Cannot call a class as a function"); | ||
} | ||
}; | ||
var createClass = function () { | ||
function defineProperties(target, props) { | ||
for (var i = 0; i < props.length; i++) { | ||
var descriptor = props[i]; | ||
descriptor.enumerable = descriptor.enumerable || false; | ||
descriptor.configurable = true; | ||
if ("value" in descriptor) descriptor.writable = true; | ||
Object.defineProperty(target, descriptor.key, descriptor); | ||
} | ||
} | ||
return function (Constructor, protoProps, staticProps) { | ||
if (protoProps) defineProperties(Constructor.prototype, protoProps); | ||
if (staticProps) defineProperties(Constructor, staticProps); | ||
return Constructor; | ||
}; | ||
}(); | ||
var toConsumableArray = function (arr) { | ||
if (Array.isArray(arr)) { | ||
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; | ||
return arr2; | ||
} else { | ||
return Array.from(arr); | ||
} | ||
}; | ||
/** | ||
* Merge an array of objects into one. | ||
* | ||
* @param {Array<Object>} arr | ||
* @return {Object} | ||
*/ | ||
function mergeObjects(arr) { | ||
return arr.reduce(function (prev, obj) { | ||
Object.keys(obj).forEach(function (key) { | ||
var existing = prev[key]; | ||
if (existing) { | ||
// allow multiple mutation objects to contain duplicate | ||
// handlers for the same mutation type | ||
if (Array.isArray(existing)) { | ||
prev[key] = existing.concat(obj[key]); | ||
} else { | ||
prev[key] = [existing].concat(obj[key]); | ||
} | ||
} else { | ||
prev[key] = obj[key]; | ||
} | ||
}); | ||
return prev; | ||
}, {}); | ||
} | ||
/** | ||
* Check whether the given value is Object or not | ||
* | ||
* @param {*} obj | ||
* @return {Boolean} | ||
*/ | ||
function isObject(obj) { | ||
return obj !== null && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object'; | ||
} | ||
/** | ||
* Get state sub tree by given keys. | ||
* | ||
* @param {Object} state | ||
* @param {Array<String>} nestedKeys | ||
* @return {Object} | ||
*/ | ||
function getNestedState(state, nestedKeys) { | ||
return nestedKeys.reduce(function (state, key) { | ||
return state[key]; | ||
}, state); | ||
} | ||
/** | ||
* Hacks to get access to Vue internals. | ||
* Maybe we should expose these... | ||
*/ | ||
var Watcher = void 0; | ||
function getWatcher(vm) { | ||
if (!Watcher) { | ||
var noop = function noop() {}; | ||
var unwatch = vm.$watch(noop, noop); | ||
Watcher = vm._watchers[0].constructor; | ||
unwatch(); | ||
} | ||
return Watcher; | ||
} | ||
var Dep = void 0; | ||
function getDep(vm) { | ||
if (!Dep) { | ||
Dep = vm._data.__ob__.dep.constructor; | ||
} | ||
return Dep; | ||
} | ||
var hook = typeof window !== 'undefined' && window.__VUE_DEVTOOLS_GLOBAL_HOOK__; | ||
@@ -144,3 +29,3 @@ | ||
function override (Vue) { | ||
function applyMixin (Vue) { | ||
var version = Number(Vue.version.split('.')[0]); | ||
@@ -171,210 +56,142 @@ | ||
var options = this.$options; | ||
var store = options.store; | ||
var vuex = options.vuex; | ||
// store injection | ||
if (store) { | ||
this.$store = store; | ||
if (options.store) { | ||
this.$store = options.store; | ||
} else if (options.parent && options.parent.$store) { | ||
this.$store = options.parent.$store; | ||
} | ||
// vuex option handling | ||
if (vuex) { | ||
if (!this.$store) { | ||
console.warn('[vuex] store not injected. make sure to ' + 'provide the store option in your root component.'); | ||
} | ||
var state = vuex.state; | ||
var actions = vuex.actions; | ||
var getters = vuex.getters; | ||
// handle deprecated state option | ||
} | ||
} | ||
if (state && !getters) { | ||
console.warn('[vuex] vuex.state option will been deprecated in 1.0. ' + 'Use vuex.getters instead.'); | ||
getters = state; | ||
function mapGetters(getters) { | ||
var res = {}; | ||
normalizeMap(getters).forEach(function (_ref) { | ||
var key = _ref.key; | ||
var val = _ref.val; | ||
res[key] = function mappedGetter() { | ||
if (!(val in this.$store.getters)) { | ||
console.error("[vuex] unknown getter: " + val); | ||
} | ||
// getters | ||
if (getters) { | ||
options.computed = options.computed || {}; | ||
for (var key in getters) { | ||
defineVuexGetter(this, key, getters[key]); | ||
} | ||
} | ||
// actions | ||
if (actions) { | ||
options.methods = options.methods || {}; | ||
for (var _key in actions) { | ||
options.methods[_key] = makeBoundAction(this.$store, actions[_key], _key); | ||
} | ||
} | ||
} | ||
} | ||
return this.$store.getters[val]; | ||
}; | ||
}); | ||
return res; | ||
} | ||
/** | ||
* Setter for all getter properties. | ||
*/ | ||
function mapActions(actions) { | ||
var res = {}; | ||
normalizeMap(actions).forEach(function (_ref2) { | ||
var key = _ref2.key; | ||
var val = _ref2.val; | ||
function setter() { | ||
throw new Error('vuex getter properties are read-only.'); | ||
} | ||
res[key] = function mappedAction() { | ||
var _$store; | ||
/** | ||
* Define a Vuex getter on an instance. | ||
* | ||
* @param {Vue} vm | ||
* @param {String} key | ||
* @param {Function} getter | ||
*/ | ||
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
function defineVuexGetter(vm, key, getter) { | ||
if (typeof getter !== 'function') { | ||
console.warn('[vuex] Getter bound to key \'vuex.getters.' + key + '\' is not a function.'); | ||
} else { | ||
Object.defineProperty(vm, key, { | ||
enumerable: true, | ||
configurable: true, | ||
get: makeComputedGetter(vm.$store, getter), | ||
set: setter | ||
}); | ||
} | ||
} | ||
return (_$store = this.$store).dispatch.apply(_$store, [val].concat(args)); | ||
}; | ||
}); | ||
return res; | ||
} | ||
/** | ||
* Make a computed getter, using the same caching mechanism of computed | ||
* properties. In addition, it is cached on the raw getter function using | ||
* the store's unique cache id. This makes the same getter shared | ||
* across all components use the same underlying watcher, and makes | ||
* the getter evaluated only once during every flush. | ||
* | ||
* @param {Store} store | ||
* @param {Function} getter | ||
*/ | ||
function normalizeMap(map) { | ||
return Array.isArray(map) ? map.map(function (key) { | ||
return { key: key, val: key }; | ||
}) : Object.keys(map).map(function (key) { | ||
return { key: key, val: map[key] }; | ||
}); | ||
} | ||
function makeComputedGetter(store, getter) { | ||
var id = store._getterCacheId; | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { | ||
return typeof obj; | ||
} : function (obj) { | ||
return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; | ||
}; | ||
// cached | ||
if (getter[id]) { | ||
return getter[id]; | ||
} | ||
var vm = store._vm; | ||
var Watcher = getWatcher(vm); | ||
var Dep = getDep(vm); | ||
var watcher = new Watcher(vm, function (vm) { | ||
return getter(vm.state); | ||
}, null, { lazy: true }); | ||
var computedGetter = function computedGetter() { | ||
if (watcher.dirty) { | ||
watcher.evaluate(); | ||
} | ||
if (Dep.target) { | ||
watcher.depend(); | ||
} | ||
return watcher.value; | ||
}; | ||
getter[id] = computedGetter; | ||
return computedGetter; | ||
var classCallCheck = function (instance, Constructor) { | ||
if (!(instance instanceof Constructor)) { | ||
throw new TypeError("Cannot call a class as a function"); | ||
} | ||
}; | ||
/** | ||
* Make a bound-to-store version of a raw action function. | ||
* | ||
* @param {Store} store | ||
* @param {Function} action | ||
* @param {String} key | ||
*/ | ||
function makeBoundAction(store, action, key) { | ||
if (typeof action !== 'function') { | ||
console.warn('[vuex] Action bound to key \'vuex.actions.' + key + '\' is not a function.'); | ||
var createClass = function () { | ||
function defineProperties(target, props) { | ||
for (var i = 0; i < props.length; i++) { | ||
var descriptor = props[i]; | ||
descriptor.enumerable = descriptor.enumerable || false; | ||
descriptor.configurable = true; | ||
if ("value" in descriptor) descriptor.writable = true; | ||
Object.defineProperty(target, descriptor.key, descriptor); | ||
} | ||
return function vuexBoundAction() { | ||
for (var _len = arguments.length, args = Array(_len), _key2 = 0; _key2 < _len; _key2++) { | ||
args[_key2] = arguments[_key2]; | ||
} | ||
return action.call.apply(action, [this, store].concat(args)); | ||
}; | ||
} | ||
// option merging | ||
var merge = Vue.config.optionMergeStrategies.computed; | ||
Vue.config.optionMergeStrategies.vuex = function (toVal, fromVal) { | ||
if (!toVal) return fromVal; | ||
if (!fromVal) return toVal; | ||
return { | ||
getters: merge(toVal.getters, fromVal.getters), | ||
state: merge(toVal.state, fromVal.state), | ||
actions: merge(toVal.actions, fromVal.actions) | ||
}; | ||
return function (Constructor, protoProps, staticProps) { | ||
if (protoProps) defineProperties(Constructor.prototype, protoProps); | ||
if (staticProps) defineProperties(Constructor, staticProps); | ||
return Constructor; | ||
}; | ||
} | ||
}(); | ||
var Vue = void 0; | ||
var uid = 0; | ||
var Vue = void 0; // bind on install | ||
var Store = function () { | ||
/** | ||
* @param {Object} options | ||
* - {Object} state | ||
* - {Object} actions | ||
* - {Object} mutations | ||
* - {Array} plugins | ||
* - {Boolean} strict | ||
*/ | ||
function Store() { | ||
var _this = this; | ||
var _ref = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; | ||
var _ref$state = _ref.state; | ||
var state = _ref$state === undefined ? {} : _ref$state; | ||
var _ref$mutations = _ref.mutations; | ||
var mutations = _ref$mutations === undefined ? {} : _ref$mutations; | ||
var _ref$modules = _ref.modules; | ||
var modules = _ref$modules === undefined ? {} : _ref$modules; | ||
var _ref$plugins = _ref.plugins; | ||
var plugins = _ref$plugins === undefined ? [] : _ref$plugins; | ||
var _ref$strict = _ref.strict; | ||
var strict = _ref$strict === undefined ? false : _ref$strict; | ||
var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; | ||
classCallCheck(this, Store); | ||
this._getterCacheId = 'vuex_store_' + uid++; | ||
this._dispatching = false; | ||
this._rootMutations = this._mutations = mutations; | ||
this._modules = modules; | ||
if (!Vue) { | ||
throw new Error('[vuex] must call Vue.use(Vuex) before creating a store instance.'); | ||
} | ||
if (typeof Promise === 'undefined') { | ||
throw new Error('[vuex] vuex requires a Promise polyfill in this browser.'); | ||
} | ||
var _options$state = options.state; | ||
var state = _options$state === undefined ? {} : _options$state; | ||
var _options$modules = options.modules; | ||
var modules = _options$modules === undefined ? {} : _options$modules; | ||
var _options$plugins = options.plugins; | ||
var plugins = _options$plugins === undefined ? [] : _options$plugins; | ||
var _options$strict = options.strict; | ||
var strict = _options$strict === undefined ? false : _options$strict; | ||
// store internal state | ||
this._options = options; | ||
this._committing = false; | ||
this._actions = Object.create(null); | ||
this._mutations = Object.create(null); | ||
this._subscribers = []; | ||
// bind dispatch to self | ||
// bind commit and dispatch to self | ||
var store = this; | ||
var dispatch = this.dispatch; | ||
this.dispatch = function () { | ||
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
var commit = this.commit; | ||
dispatch.apply(_this, args); | ||
this.dispatch = function boundDispatch(type, payload) { | ||
return dispatch.call(store, type, payload); | ||
}; | ||
// use a Vue instance to store the state tree | ||
// suppress warnings just in case the user has added | ||
// some funky global mixins | ||
if (!Vue) { | ||
throw new Error('[vuex] must call Vue.use(Vuex) before creating a store instance.'); | ||
} | ||
var silent = Vue.config.silent; | ||
Vue.config.silent = true; | ||
this._vm = new Vue({ | ||
data: { | ||
state: state | ||
} | ||
}); | ||
Vue.config.silent = silent; | ||
this._setupModuleState(state, modules); | ||
this._setupModuleMutations(modules); | ||
// add extra warnings in strict mode | ||
if (strict) { | ||
this._setupMutationCheck(); | ||
} | ||
this.commit = function boundCommit(type, payload) { | ||
return commit.call(store, type, payload); | ||
}; | ||
// init state and getters | ||
var getters = extractModuleGetters(options.getters, modules); | ||
initStoreState(this, state, getters); | ||
// apply root module | ||
this.module([], options); | ||
// strict mode | ||
if (strict) enableStrictMode(this); | ||
// apply plugins | ||
devtoolPlugin(this); | ||
plugins.forEach(function (plugin) { | ||
plugins.concat(devtoolPlugin).forEach(function (plugin) { | ||
return plugin(_this); | ||
@@ -384,104 +201,131 @@ }); | ||
/** | ||
* Getter for the entire state tree. | ||
* Read only. | ||
* | ||
* @return {Object} | ||
*/ | ||
createClass(Store, [{ | ||
key: 'replaceState', | ||
/** | ||
* Replace root state. | ||
* | ||
* @param {Object} state | ||
*/ | ||
value: function replaceState(state) { | ||
this._dispatching = true; | ||
this._committing = true; | ||
this._vm.state = state; | ||
this._dispatching = false; | ||
this._committing = false; | ||
} | ||
/** | ||
* Dispatch an action. | ||
* | ||
* @param {String} type | ||
*/ | ||
}, { | ||
key: 'dispatch', | ||
value: function dispatch(type) { | ||
key: 'module', | ||
value: function module(path, _module, hot) { | ||
var _this2 = this; | ||
for (var _len2 = arguments.length, payload = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { | ||
payload[_key2 - 1] = arguments[_key2]; | ||
if (typeof path === 'string') path = [path]; | ||
if (!Array.isArray(path)) { | ||
throw new Error('[vuex] module path must be a string or an Array.'); | ||
} | ||
var silent = false; | ||
var isObjectStyleDispatch = false; | ||
// compatibility for object actions, e.g. FSA | ||
if ((typeof type === 'undefined' ? 'undefined' : _typeof(type)) === 'object' && type.type && arguments.length === 1) { | ||
isObjectStyleDispatch = true; | ||
payload = type; | ||
if (type.silent) silent = true; | ||
type = type.type; | ||
var isRoot = !path.length; | ||
var state = _module.state; | ||
var actions = _module.actions; | ||
var mutations = _module.mutations; | ||
var modules = _module.modules; | ||
// set state | ||
if (!isRoot && !hot) { | ||
var parentState = getNestedState(this.state, path.slice(0, -1)); | ||
if (!parentState) debugger; | ||
var moduleName = path[path.length - 1]; | ||
Vue.set(parentState, moduleName, state || {}); | ||
} | ||
var handler = this._mutations[type]; | ||
var state = this.state; | ||
if (handler) { | ||
this._dispatching = true; | ||
// apply the mutation | ||
if (Array.isArray(handler)) { | ||
handler.forEach(function (h) { | ||
isObjectStyleDispatch ? h(state, payload) : h.apply(undefined, [state].concat(toConsumableArray(payload))); | ||
}); | ||
} else { | ||
isObjectStyleDispatch ? handler(state, payload) : handler.apply(undefined, [state].concat(toConsumableArray(payload))); | ||
} | ||
this._dispatching = false; | ||
if (!silent) { | ||
(function () { | ||
var mutation = isObjectStyleDispatch ? payload : { type: type, payload: payload }; | ||
_this2._subscribers.forEach(function (sub) { | ||
return sub(mutation, state); | ||
}); | ||
})(); | ||
} | ||
} else { | ||
console.warn('[vuex] Unknown mutation: ' + type); | ||
if (mutations) { | ||
Object.keys(mutations).forEach(function (key) { | ||
_this2.mutation(key, mutations[key], path); | ||
}); | ||
} | ||
if (actions) { | ||
Object.keys(actions).forEach(function (key) { | ||
_this2.action(key, actions[key], path); | ||
}); | ||
} | ||
if (modules) { | ||
Object.keys(modules).forEach(function (key) { | ||
_this2.module(path.concat(key), modules[key], hot); | ||
}); | ||
} | ||
} | ||
}, { | ||
key: 'mutation', | ||
value: function mutation(type, handler) { | ||
var path = arguments.length <= 2 || arguments[2] === undefined ? [] : arguments[2]; | ||
/** | ||
* Watch state changes on the store. | ||
* Same API as Vue's $watch, except when watching a function, | ||
* the function gets the state as the first argument. | ||
* | ||
* @param {Function} fn | ||
* @param {Function} cb | ||
* @param {Object} [options] | ||
*/ | ||
var entry = this._mutations[type] || (this._mutations[type] = []); | ||
var store = this; | ||
entry.push(function wrappedMutationHandler(payload) { | ||
handler(getNestedState(store.state, path), payload); | ||
}); | ||
} | ||
}, { | ||
key: 'action', | ||
value: function action(type, handler) { | ||
var path = arguments.length <= 2 || arguments[2] === undefined ? [] : arguments[2]; | ||
var entry = this._actions[type] || (this._actions[type] = []); | ||
var store = this; | ||
var dispatch = this.dispatch; | ||
var commit = this.commit; | ||
entry.push(function wrappedActionHandler(payload, cb) { | ||
var res = handler({ | ||
dispatch: dispatch, | ||
commit: commit, | ||
state: getNestedState(store.state, path) | ||
}, payload, cb); | ||
if (!isPromise(res)) { | ||
res = Promise.resolve(res); | ||
} | ||
return res.catch(function (err) { | ||
console.error('[vuex] error in Promise returned from action "' + type + '":'); | ||
console.error(err); | ||
}); | ||
}); | ||
} | ||
}, { | ||
key: 'watch', | ||
value: function watch(fn, cb, options) { | ||
key: 'commit', | ||
value: function commit(type, payload) { | ||
var _this3 = this; | ||
if (typeof fn !== 'function') { | ||
console.error('Vuex store.watch only accepts function.'); | ||
// check object-style commit | ||
var mutation = void 0; | ||
if (isObject(type) && type.type) { | ||
payload = mutation = type; | ||
type = type.type; | ||
} else { | ||
mutation = { type: type, payload: payload }; | ||
} | ||
var entry = this._mutations[type]; | ||
if (!entry) { | ||
console.error('[vuex] unknown mutation type: ' + type); | ||
return; | ||
} | ||
return this._vm.$watch(function () { | ||
return fn(_this3.state); | ||
}, cb, options); | ||
this._committing = true; | ||
entry.forEach(function commitIterator(handler) { | ||
handler(payload); | ||
}); | ||
this._committing = false; | ||
if (!payload || !payload.silent) { | ||
this._subscribers.forEach(function (sub) { | ||
return sub(mutation, _this3.state); | ||
}); | ||
} | ||
} | ||
/** | ||
* Subscribe to state changes. Fires after every mutation. | ||
*/ | ||
}, { | ||
key: 'dispatch', | ||
value: function dispatch(type, payload) { | ||
var entry = this._actions[type]; | ||
if (!entry) { | ||
debugger; | ||
console.error('[vuex] unknown action type: ' + type); | ||
return; | ||
} | ||
return entry.length > 1 ? Promise.all(entry.map(function (handler) { | ||
return handler(payload); | ||
})) : entry[0](payload); | ||
} | ||
}, { | ||
key: 'subscribe', | ||
@@ -500,136 +344,44 @@ value: function subscribe(fn) { | ||
} | ||
/** | ||
* Hot update mutations & modules. | ||
* | ||
* @param {Object} options | ||
* - {Object} [mutations] | ||
* - {Object} [modules] | ||
*/ | ||
}, { | ||
key: 'hotUpdate', | ||
value: function hotUpdate() { | ||
var _ref2 = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; | ||
var mutations = _ref2.mutations; | ||
var modules = _ref2.modules; | ||
this._rootMutations = this._mutations = mutations || this._rootMutations; | ||
this._setupModuleMutations(modules || this._modules); | ||
} | ||
/** | ||
* Attach sub state tree of each module to the root tree. | ||
* | ||
* @param {Object} state | ||
* @param {Object} modules | ||
*/ | ||
}, { | ||
key: '_setupModuleState', | ||
value: function _setupModuleState(state, modules) { | ||
value: function hotUpdate(newOptions) { | ||
var _this4 = this; | ||
if (!isObject(modules)) return; | ||
Object.keys(modules).forEach(function (key) { | ||
var module = modules[key]; | ||
// set this module's state | ||
Vue.set(state, key, module.state || {}); | ||
// retrieve nested modules | ||
_this4._setupModuleState(state[key], module.modules); | ||
}); | ||
} | ||
/** | ||
* Bind mutations for each module to its sub tree and | ||
* merge them all into one final mutations map. | ||
* | ||
* @param {Object} updatedModules | ||
*/ | ||
}, { | ||
key: '_setupModuleMutations', | ||
value: function _setupModuleMutations(updatedModules) { | ||
var modules = this._modules; | ||
Object.keys(updatedModules).forEach(function (key) { | ||
modules[key] = updatedModules[key]; | ||
}); | ||
var updatedMutations = this._createModuleMutations(modules, []); | ||
this._mutations = mergeObjects([this._rootMutations].concat(toConsumableArray(updatedMutations))); | ||
} | ||
/** | ||
* Helper method for _setupModuleMutations. | ||
* The method retrieve nested sub modules and | ||
* bind each mutations to its sub tree recursively. | ||
* | ||
* @param {Object} modules | ||
* @param {Array<String>} nestedKeys | ||
* @return {Array<Object>} | ||
*/ | ||
}, { | ||
key: '_createModuleMutations', | ||
value: function _createModuleMutations(modules, nestedKeys) { | ||
var _this5 = this; | ||
if (!isObject(modules)) return []; | ||
return Object.keys(modules).map(function (key) { | ||
var module = modules[key]; | ||
var newNestedKeys = nestedKeys.concat(key); | ||
// retrieve nested modules | ||
var nestedMutations = _this5._createModuleMutations(module.modules, newNestedKeys); | ||
if (!module || !module.mutations) { | ||
return mergeObjects(nestedMutations); | ||
this._actions = Object.create(null); | ||
this._mutations = Object.create(null); | ||
var options = this._options; | ||
if (newOptions.actions) { | ||
options.actions = newOptions.actions; | ||
} | ||
if (newOptions.mutations) { | ||
options.mutations = newOptions.mutations; | ||
} | ||
if (newOptions.modules) { | ||
for (var key in newOptions.modules) { | ||
options.modules[key] = newOptions.modules[key]; | ||
} | ||
} | ||
this.module([], options, true); | ||
// bind mutations to sub state tree | ||
var mutations = {}; | ||
Object.keys(module.mutations).forEach(function (name) { | ||
var original = module.mutations[name]; | ||
mutations[name] = function (state) { | ||
for (var _len3 = arguments.length, args = Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { | ||
args[_key3 - 1] = arguments[_key3]; | ||
} | ||
original.apply(undefined, [getNestedState(state, newNestedKeys)].concat(args)); | ||
}; | ||
}); | ||
// merge mutations of this module and nested modules | ||
return mergeObjects([mutations].concat(toConsumableArray(nestedMutations))); | ||
}); | ||
// update getters | ||
var getters = extractModuleGetters(newOptions.getters, newOptions.modules); | ||
if (Object.keys(getters).length) { | ||
(function () { | ||
var oldVm = _this4._vm; | ||
initStoreState(_this4, _this4.state, getters); | ||
if (_this4.strict) { | ||
enableStrictMode(_this4); | ||
} | ||
// dispatch changes in all subscribed watchers | ||
// to force getter re-evaluation. | ||
_this4._committing = true; | ||
oldVm.state = null; | ||
_this4._committing = false; | ||
Vue.nextTick(function () { | ||
return oldVm.$destroy(); | ||
}); | ||
})(); | ||
} | ||
} | ||
/** | ||
* Setup mutation check: if the vuex instance's state is mutated | ||
* outside of a mutation handler, we throw en error. This effectively | ||
* enforces all mutations to the state to be trackable and hot-reloadble. | ||
* However, this comes at a run time cost since we are doing a deep | ||
* watch on the entire state tree, so it is only enalbed with the | ||
* strict option is set to true. | ||
*/ | ||
}, { | ||
key: '_setupMutationCheck', | ||
value: function _setupMutationCheck() { | ||
var _this6 = this; | ||
var Watcher = getWatcher(this._vm); | ||
/* eslint-disable no-new */ | ||
new Watcher(this._vm, 'state', function () { | ||
if (!_this6._dispatching) { | ||
throw new Error('[vuex] Do not mutate vuex store state outside mutation handlers.'); | ||
} | ||
}, { deep: true, sync: true }); | ||
/* eslint-enable no-new */ | ||
} | ||
}, { | ||
key: 'state', | ||
@@ -646,9 +398,86 @@ get: function get() { | ||
function initStoreState(store, state, getters) { | ||
// bind getters | ||
store.getters = {}; | ||
var computed = {}; | ||
Object.keys(getters).forEach(function (key) { | ||
var fn = getters[key]; | ||
// use computed to leverage its lazy-caching mechanism | ||
computed[key] = function () { | ||
return fn(store._vm.state); | ||
}; | ||
Object.defineProperty(store.getters, key, { | ||
get: function get() { | ||
return store._vm[key]; | ||
} | ||
}); | ||
}); | ||
// use a Vue instance to store the state tree | ||
// suppress warnings just in case the user has added | ||
// some funky global mixins | ||
var silent = Vue.config.silent; | ||
Vue.config.silent = true; | ||
store._vm = new Vue({ | ||
data: { state: state }, | ||
computed: computed | ||
}); | ||
Vue.config.silent = silent; | ||
} | ||
function extractModuleGetters() { | ||
var getters = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; | ||
var modules = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; | ||
var path = arguments.length <= 2 || arguments[2] === undefined ? [] : arguments[2]; | ||
if (!modules) return getters; | ||
Object.keys(modules).forEach(function (key) { | ||
var module = modules[key]; | ||
var modulePath = path.concat(key); | ||
if (module.getters) { | ||
Object.keys(module.getters).forEach(function (getterKey) { | ||
var rawGetter = module.getters[getterKey]; | ||
if (getters[getterKey]) { | ||
console.error('[vuex] duplicate getter key: ' + getterKey); | ||
return; | ||
} | ||
getters[getterKey] = function wrappedGetter(state) { | ||
return rawGetter(getNestedState(state, modulePath)); | ||
}; | ||
}); | ||
} | ||
extractModuleGetters(getters, module.modules, modulePath); | ||
}); | ||
return getters; | ||
} | ||
function enableStrictMode(store) { | ||
store._vm.$watch('state', function () { | ||
if (!store._committing) { | ||
throw new Error('[vuex] Do not mutate vuex store state outside mutation handlers.'); | ||
} | ||
}, { deep: true, sync: true }); | ||
} | ||
function isObject(obj) { | ||
return obj !== null && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object'; | ||
} | ||
function isPromise(val) { | ||
return val && typeof val.then === 'function'; | ||
} | ||
function getNestedState(state, path) { | ||
return path.reduce(function (state, key) { | ||
return state[key]; | ||
}, state); | ||
} | ||
function install(_Vue) { | ||
if (Vue) { | ||
console.warn('[vuex] already installed. Vue.use(Vuex) should be called only once.'); | ||
console.error('[vuex] already installed. Vue.use(Vuex) should be called only once.'); | ||
return; | ||
} | ||
Vue = _Vue; | ||
override(Vue); | ||
applyMixin(Vue); | ||
} | ||
@@ -663,3 +492,5 @@ | ||
Store: Store, | ||
install: install | ||
install: install, | ||
mapGetters: mapGetters, | ||
mapActions: mapActions | ||
}; | ||
@@ -666,0 +497,0 @@ |
/*! | ||
* Vuex v1.0.0-rc.2 | ||
* Vuex v2.0.0-rc.1 | ||
* (c) 2016 Evan You | ||
* Released under the MIT License. | ||
*/ | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.Vuex=e()}(this,function(){"use strict";function t(t){return t.reduce(function(t,e){return Object.keys(e).forEach(function(n){var o=t[n];o?Array.isArray(o)?t[n]=o.concat(e[n]):t[n]=[o].concat(e[n]):t[n]=e[n]}),t},{})}function e(t){return null!==t&&"object"===("undefined"==typeof t?"undefined":s(t))}function n(t,e){return e.reduce(function(t,e){return t[e]},t)}function o(t){if(!d){var e=function(){},n=t.$watch(e,e);d=t._watchers[0].constructor,n()}return d}function i(t){return v||(v=t._data.__ob__.dep.constructor),v}function r(t){h&&(h.emit("vuex:init",t),h.on("vuex:travel-to-state",function(e){t.replaceState(e)}),t.subscribe(function(t,e){h.emit("vuex:mutation",t,e)}))}function u(t){function e(){var t=this.$options,e=t.store,n=t.vuex;if(e?this.$store=e:t.parent&&t.parent.$store&&(this.$store=t.parent.$store),n){this.$store||console.warn("[vuex] store not injected. make sure to provide the store option in your root component.");var o=n.state,i=n.actions,u=n.getters;if(o&&!u&&(console.warn("[vuex] vuex.state option will been deprecated in 1.0. Use vuex.getters instead."),u=o),u){t.computed=t.computed||{};for(var s in u)r(this,s,u[s])}if(i){t.methods=t.methods||{};for(var c in i)t.methods[c]=a(this.$store,i[c],c)}}}function n(){throw new Error("vuex getter properties are read-only.")}function r(t,e,o){"function"!=typeof o?console.warn("[vuex] Getter bound to key 'vuex.getters."+e+"' is not a function."):Object.defineProperty(t,e,{enumerable:!0,configurable:!0,get:u(t.$store,o),set:n})}function u(t,e){var n=t._getterCacheId;if(e[n])return e[n];var r=t._vm,u=o(r),a=i(r),s=new u(r,function(t){return e(t.state)},null,{lazy:!0}),c=function(){return s.dirty&&s.evaluate(),a.target&&s.depend(),s.value};return e[n]=c,c}function a(t,e,n){return"function"!=typeof e&&console.warn("[vuex] Action bound to key 'vuex.actions."+n+"' is not a function."),function(){for(var n=arguments.length,o=Array(n),i=0;i<n;i++)o[i]=arguments[i];return e.call.apply(e,[this,t].concat(o))}}var s=Number(t.version.split(".")[0]);if(s>=2){var c=t.config._lifecycleHooks.indexOf("init")>-1;t.mixin(c?{init:e}:{beforeCreate:e})}else!function(){var n=t.prototype._init;t.prototype._init=function(){var t=arguments.length<=0||void 0===arguments[0]?{}:arguments[0];t.init=t.init?[e].concat(t.init):e,n.call(this,t)}}();var f=t.config.optionMergeStrategies.computed;t.config.optionMergeStrategies.vuex=function(t,e){return t?e?{getters:f(t.getters,e.getters),state:f(t.state,e.state),actions:f(t.actions,e.actions)}:t:e}}function a(t){return p?void console.warn("[vuex] already installed. Vue.use(Vuex) should be called only once."):(p=t,void u(p))}var s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol?"symbol":typeof t},c=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},f=function(){function t(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}return function(e,n,o){return n&&t(e.prototype,n),o&&t(e,o),e}}(),l=function(t){if(Array.isArray(t)){for(var e=0,n=Array(t.length);e<t.length;e++)n[e]=t[e];return n}return Array.from(t)},d=void 0,v=void 0,h="undefined"!=typeof window&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__,p=void 0,y=0,_=function(){function i(){var t=this,e=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=e.state,o=void 0===n?{}:n,u=e.mutations,a=void 0===u?{}:u,s=e.modules,f=void 0===s?{}:s,l=e.plugins,d=void 0===l?[]:l,v=e.strict,h=void 0!==v&&v;c(this,i),this._getterCacheId="vuex_store_"+y++,this._dispatching=!1,this._rootMutations=this._mutations=a,this._modules=f,this._subscribers=[];var _=this.dispatch;if(this.dispatch=function(){for(var e=arguments.length,n=Array(e),o=0;o<e;o++)n[o]=arguments[o];_.apply(t,n)},!p)throw new Error("[vuex] must call Vue.use(Vuex) before creating a store instance.");var m=p.config.silent;p.config.silent=!0,this._vm=new p({data:{state:o}}),p.config.silent=m,this._setupModuleState(o,f),this._setupModuleMutations(f),h&&this._setupMutationCheck(),r(this),d.forEach(function(e){return e(t)})}return f(i,[{key:"replaceState",value:function(t){this._dispatching=!0,this._vm.state=t,this._dispatching=!1}},{key:"dispatch",value:function(t){for(var e=this,n=arguments.length,o=Array(n>1?n-1:0),i=1;i<n;i++)o[i-1]=arguments[i];var r=!1,u=!1;"object"===("undefined"==typeof t?"undefined":s(t))&&t.type&&1===arguments.length&&(u=!0,o=t,t.silent&&(r=!0),t=t.type);var a=this._mutations[t],c=this.state;a?(this._dispatching=!0,Array.isArray(a)?a.forEach(function(t){u?t(c,o):t.apply(void 0,[c].concat(l(o)))}):u?a(c,o):a.apply(void 0,[c].concat(l(o))),this._dispatching=!1,r||!function(){var n=u?o:{type:t,payload:o};e._subscribers.forEach(function(t){return t(n,c)})}()):console.warn("[vuex] Unknown mutation: "+t)}},{key:"watch",value:function(t,e,n){var o=this;return"function"!=typeof t?void console.error("Vuex store.watch only accepts function."):this._vm.$watch(function(){return t(o.state)},e,n)}},{key:"subscribe",value:function(t){var e=this._subscribers;return e.indexOf(t)<0&&e.push(t),function(){var n=e.indexOf(t);n>-1&&e.splice(n,1)}}},{key:"hotUpdate",value:function(){var t=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],e=t.mutations,n=t.modules;this._rootMutations=this._mutations=e||this._rootMutations,this._setupModuleMutations(n||this._modules)}},{key:"_setupModuleState",value:function(t,n){var o=this;e(n)&&Object.keys(n).forEach(function(e){var i=n[e];p.set(t,e,i.state||{}),o._setupModuleState(t[e],i.modules)})}},{key:"_setupModuleMutations",value:function(e){var n=this._modules;Object.keys(e).forEach(function(t){n[t]=e[t]});var o=this._createModuleMutations(n,[]);this._mutations=t([this._rootMutations].concat(l(o)))}},{key:"_createModuleMutations",value:function(o,i){var r=this;return e(o)?Object.keys(o).map(function(e){var u=o[e],a=i.concat(e),s=r._createModuleMutations(u.modules,a);if(!u||!u.mutations)return t(s);var c={};return Object.keys(u.mutations).forEach(function(t){var e=u.mutations[t];c[t]=function(t){for(var o=arguments.length,i=Array(o>1?o-1:0),r=1;r<o;r++)i[r-1]=arguments[r];e.apply(void 0,[n(t,a)].concat(i))}}),t([c].concat(l(s)))}):[]}},{key:"_setupMutationCheck",value:function(){var t=this,e=o(this._vm);new e(this._vm,"state",function(){if(!t._dispatching)throw new Error("[vuex] Do not mutate vuex store state outside mutation handlers.")},{deep:!0,sync:!0})}},{key:"state",get:function(){return this._vm.state},set:function(t){throw new Error("[vuex] Use store.replaceState() to explicit replace store state.")}}]),i}();"undefined"!=typeof window&&window.Vue&&a(window.Vue);var m={Store:_,install:a};return m}); | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.Vuex=e()}(this,function(){"use strict";function t(t){v&&(v.emit("vuex:init",t),v.on("vuex:travel-to-state",function(e){t.replaceState(e)}),t.subscribe(function(t,e){v.emit("vuex:mutation",t,e)}))}function e(t){function e(){var t=this.$options;t.store?this.$store=t.store:t.parent&&t.parent.$store&&(this.$store=t.parent.$store)}var n=Number(t.version.split(".")[0]);if(n>=2){var o=t.config._lifecycleHooks.indexOf("init")>-1;t.mixin(o?{init:e}:{beforeCreate:e})}else!function(){var n=t.prototype._init;t.prototype._init=function(){var t=arguments.length<=0||void 0===arguments[0]?{}:arguments[0];t.init=t.init?[e].concat(t.init):e,n.call(this,t)}}()}function n(t){var e={};return i(t).forEach(function(t){var n=t.key,o=t.val;e[n]=function(){return o in this.$store.getters||console.error("[vuex] unknown getter: "+o),this.$store.getters[o]}}),e}function o(t){var e={};return i(t).forEach(function(t){var n=t.key,o=t.val;e[n]=function(){for(var t,e=arguments.length,n=Array(e),i=0;i<e;i++)n[i]=arguments[i];return(t=this.$store).dispatch.apply(t,[o].concat(n))}}),e}function i(t){return Array.isArray(t)?t.map(function(t){return{key:t,val:t}}):Object.keys(t).map(function(e){return{key:e,val:t[e]}})}function r(t,e,n){t.getters={};var o={};Object.keys(n).forEach(function(e){var i=n[e];o[e]=function(){return i(t._vm.state)},Object.defineProperty(t.getters,e,{get:function(){return t._vm[e]}})});var i=y.config.silent;y.config.silent=!0,t._vm=new y({data:{state:e},computed:o}),y.config.silent=i}function s(){var t=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],e=arguments.length<=1||void 0===arguments[1]?{}:arguments[1],n=arguments.length<=2||void 0===arguments[2]?[]:arguments[2];return e?(Object.keys(e).forEach(function(o){var i=e[o],r=n.concat(o);i.getters&&Object.keys(i.getters).forEach(function(e){var n=i.getters[e];return t[e]?void console.error("[vuex] duplicate getter key: "+e):void(t[e]=function(t){return n(f(t,r))})}),s(t,i.modules,r)}),t):t}function u(t){t._vm.$watch("state",function(){if(!t._committing)throw new Error("[vuex] Do not mutate vuex store state outside mutation handlers.")},{deep:!0,sync:!0})}function c(t){return null!==t&&"object"===("undefined"==typeof t?"undefined":h(t))}function a(t){return t&&"function"==typeof t.then}function f(t,e){return e.reduce(function(t,e){return t[e]},t)}function l(t){return y?void console.error("[vuex] already installed. Vue.use(Vuex) should be called only once."):(y=t,void e(y))}var v="undefined"!=typeof window&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__,h="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol?"symbol":typeof t},m=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},d=function(){function t(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}return function(e,n,o){return n&&t(e.prototype,n),o&&t(e,o),e}}(),y=void 0,p=function(){function e(){var n=this,o=arguments.length<=0||void 0===arguments[0]?{}:arguments[0];if(m(this,e),!y)throw new Error("[vuex] must call Vue.use(Vuex) before creating a store instance.");if("undefined"==typeof Promise)throw new Error("[vuex] vuex requires a Promise polyfill in this browser.");var i=o.state,c=void 0===i?{}:i,a=o.modules,f=void 0===a?{}:a,l=o.plugins,v=void 0===l?[]:l,h=o.strict,d=void 0!==h&&h;this._options=o,this._committing=!1,this._actions=Object.create(null),this._mutations=Object.create(null),this._subscribers=[];var p=this,g=this.dispatch,b=this.commit;this.dispatch=function(t,e){return g.call(p,t,e)},this.commit=function(t,e){return b.call(p,t,e)};var _=s(o.getters,f);r(this,c,_),this.module([],o),d&&u(this),v.concat(t).forEach(function(t){return t(n)})}return d(e,[{key:"replaceState",value:function(t){this._committing=!0,this._vm.state=t,this._committing=!1}},{key:"module",value:function(t,e,n){var o=this;if("string"==typeof t&&(t=[t]),!Array.isArray(t))throw new Error("[vuex] module path must be a string or an Array.");var i=!t.length,r=e.state,s=e.actions,u=e.mutations,c=e.modules;if(!i&&!n){var a=f(this.state,t.slice(0,-1)),l=t[t.length-1];y.set(a,l,r||{})}u&&Object.keys(u).forEach(function(e){o.mutation(e,u[e],t)}),s&&Object.keys(s).forEach(function(e){o.action(e,s[e],t)}),c&&Object.keys(c).forEach(function(e){o.module(t.concat(e),c[e],n)})}},{key:"mutation",value:function(t,e){var n=arguments.length<=2||void 0===arguments[2]?[]:arguments[2],o=this._mutations[t]||(this._mutations[t]=[]),i=this;o.push(function(t){e(f(i.state,n),t)})}},{key:"action",value:function(t,e){var n=arguments.length<=2||void 0===arguments[2]?[]:arguments[2],o=this._actions[t]||(this._actions[t]=[]),i=this,r=this.dispatch,s=this.commit;o.push(function(o,u){var c=e({dispatch:r,commit:s,state:f(i.state,n)},o,u);return a(c)||(c=Promise.resolve(c)),c["catch"](function(e){console.error('[vuex] error in Promise returned from action "'+t+'":'),console.error(e)})})}},{key:"commit",value:function(t,e){var n=this,o=void 0;c(t)&&t.type?(e=o=t,t=t.type):o={type:t,payload:e};var i=this._mutations[t];return i?(this._committing=!0,i.forEach(function(t){t(e)}),this._committing=!1,void(e&&e.silent||this._subscribers.forEach(function(t){return t(o,n.state)}))):void console.error("[vuex] unknown mutation type: "+t)}},{key:"dispatch",value:function(t,e){var n=this._actions[t];return n?n.length>1?Promise.all(n.map(function(t){return t(e)})):n[0](e):void console.error("[vuex] unknown action type: "+t)}},{key:"subscribe",value:function(t){var e=this._subscribers;return e.indexOf(t)<0&&e.push(t),function(){var n=e.indexOf(t);n>-1&&e.splice(n,1)}}},{key:"hotUpdate",value:function(t){var e=this;this._actions=Object.create(null),this._mutations=Object.create(null);var n=this._options;if(t.actions&&(n.actions=t.actions),t.mutations&&(n.mutations=t.mutations),t.modules)for(var o in t.modules)n.modules[o]=t.modules[o];this.module([],n,!0);var i=s(t.getters,t.modules);Object.keys(i).length&&!function(){var t=e._vm;r(e,e.state,i),e.strict&&u(e),e._committing=!0,t.state=null,e._committing=!1,y.nextTick(function(){return t.$destroy()})}()}},{key:"state",get:function(){return this._vm.state},set:function(t){throw new Error("[vuex] Use store.replaceState() to explicit replace store state.")}}]),e}();"undefined"!=typeof window&&window.Vue&&l(window.Vue);var g={Store:p,install:l,mapGetters:n,mapActions:o};return g}); |
{ | ||
"name": "vuex", | ||
"version": "1.0.0-rc.2", | ||
"version": "2.0.0-rc.1", | ||
"description": "state management for Vue.js", | ||
@@ -19,3 +19,3 @@ "main": "dist/vuex.js", | ||
"build-examples": "BABEL_ENV=development webpack --config examples/webpack.build-all.config.js", | ||
"unit": "BABEL_ENV=development mocha test/unit/test.js --compilers js:babel-core/register", | ||
"unit": "BABEL_ENV=development mocha test/unit/test.js --compilers js:babel-core/register 2>/dev/null", | ||
"pree2e": "npm run build-examples", | ||
@@ -22,0 +22,0 @@ "e2e": "casperjs test --concise ./test/e2e", |
463
src/index.js
@@ -1,42 +0,9 @@ | ||
import { | ||
mergeObjects, isObject, | ||
getNestedState, getWatcher | ||
} from './util' | ||
import devtoolPlugin from './plugins/devtool' | ||
import override from './override' | ||
import applyMixin from './mixin' | ||
import { mapGetters, mapActions } from './helpers' | ||
let Vue | ||
let uid = 0 | ||
let Vue // bind on install | ||
class Store { | ||
/** | ||
* @param {Object} options | ||
* - {Object} state | ||
* - {Object} actions | ||
* - {Object} mutations | ||
* - {Array} plugins | ||
* - {Boolean} strict | ||
*/ | ||
constructor ({ | ||
state = {}, | ||
mutations = {}, | ||
modules = {}, | ||
plugins = [], | ||
strict = false | ||
} = {}) { | ||
this._getterCacheId = 'vuex_store_' + uid++ | ||
this._dispatching = false | ||
this._rootMutations = this._mutations = mutations | ||
this._modules = modules | ||
this._subscribers = [] | ||
// bind dispatch to self | ||
const dispatch = this.dispatch | ||
this.dispatch = (...args) => { | ||
dispatch.apply(this, args) | ||
} | ||
// use a Vue instance to store the state tree | ||
// suppress warnings just in case the user has added | ||
// some funky global mixins | ||
constructor (options = {}) { | ||
if (!Vue) { | ||
@@ -47,28 +14,47 @@ throw new Error( | ||
} | ||
const silent = Vue.config.silent | ||
Vue.config.silent = true | ||
this._vm = new Vue({ | ||
data: { | ||
state | ||
} | ||
}) | ||
Vue.config.silent = silent | ||
this._setupModuleState(state, modules) | ||
this._setupModuleMutations(modules) | ||
// add extra warnings in strict mode | ||
if (strict) { | ||
this._setupMutationCheck() | ||
if (typeof Promise === 'undefined') { | ||
throw new Error( | ||
'[vuex] vuex requires a Promise polyfill in this browser.' | ||
) | ||
} | ||
const { | ||
state = {}, | ||
modules = {}, | ||
plugins = [], | ||
strict = false | ||
} = options | ||
// store internal state | ||
this._options = options | ||
this._committing = false | ||
this._actions = Object.create(null) | ||
this._mutations = Object.create(null) | ||
this._subscribers = [] | ||
// bind commit and dispatch to self | ||
const store = this | ||
const { dispatch, commit } = this | ||
this.dispatch = function boundDispatch (type, payload) { | ||
return dispatch.call(store, type, payload) | ||
} | ||
this.commit = function boundCommit (type, payload) { | ||
return commit.call(store, type, payload) | ||
} | ||
// init state and getters | ||
const getters = extractModuleGetters(options.getters, modules) | ||
initStoreState(this, state, getters) | ||
// apply root module | ||
this.module([], options) | ||
// strict mode | ||
if (strict) enableStrictMode(this) | ||
// apply plugins | ||
devtoolPlugin(this) | ||
plugins.forEach(plugin => plugin(this)) | ||
plugins.concat(devtoolPlugin).forEach(plugin => plugin(this)) | ||
} | ||
/** | ||
* Getter for the entire state tree. | ||
* Read only. | ||
* | ||
* @return {Object} | ||
*/ | ||
get state () { | ||
@@ -82,80 +68,113 @@ return this._vm.state | ||
/** | ||
* Replace root state. | ||
* | ||
* @param {Object} state | ||
*/ | ||
replaceState (state) { | ||
this._dispatching = true | ||
this._committing = true | ||
this._vm.state = state | ||
this._dispatching = false | ||
this._committing = false | ||
} | ||
/** | ||
* Dispatch an action. | ||
* | ||
* @param {String} type | ||
*/ | ||
module (path, module, hot) { | ||
if (typeof path === 'string') path = [path] | ||
if (!Array.isArray(path)) { | ||
throw new Error('[vuex] module path must be a string or an Array.') | ||
} | ||
dispatch (type, ...payload) { | ||
let silent = false | ||
let isObjectStyleDispatch = false | ||
// compatibility for object actions, e.g. FSA | ||
if (typeof type === 'object' && type.type && arguments.length === 1) { | ||
isObjectStyleDispatch = true | ||
payload = type | ||
if (type.silent) silent = true | ||
type = type.type | ||
const isRoot = !path.length | ||
const { | ||
state, | ||
actions, | ||
mutations, | ||
modules | ||
} = module | ||
// set state | ||
if (!isRoot && !hot) { | ||
const parentState = getNestedState(this.state, path.slice(0, -1)) | ||
if (!parentState) debugger | ||
const moduleName = path[path.length - 1] | ||
Vue.set(parentState, moduleName, state || {}) | ||
} | ||
const handler = this._mutations[type] | ||
const state = this.state | ||
if (handler) { | ||
this._dispatching = true | ||
// apply the mutation | ||
if (Array.isArray(handler)) { | ||
handler.forEach(h => { | ||
isObjectStyleDispatch | ||
? h(state, payload) | ||
: h(state, ...payload) | ||
}) | ||
} else { | ||
isObjectStyleDispatch | ||
? handler(state, payload) | ||
: handler(state, ...payload) | ||
if (mutations) { | ||
Object.keys(mutations).forEach(key => { | ||
this.mutation(key, mutations[key], path) | ||
}) | ||
} | ||
if (actions) { | ||
Object.keys(actions).forEach(key => { | ||
this.action(key, actions[key], path) | ||
}) | ||
} | ||
if (modules) { | ||
Object.keys(modules).forEach(key => { | ||
this.module(path.concat(key), modules[key], hot) | ||
}) | ||
} | ||
} | ||
mutation (type, handler, path = []) { | ||
const entry = this._mutations[type] || (this._mutations[type] = []) | ||
const store = this | ||
entry.push(function wrappedMutationHandler (payload) { | ||
handler(getNestedState(store.state, path), payload) | ||
}) | ||
} | ||
action (type, handler, path = []) { | ||
const entry = this._actions[type] || (this._actions[type] = []) | ||
const store = this | ||
const { dispatch, commit } = this | ||
entry.push(function wrappedActionHandler (payload, cb) { | ||
let res = handler({ | ||
dispatch, | ||
commit, | ||
state: getNestedState(store.state, path) | ||
}, payload, cb) | ||
if (!isPromise(res)) { | ||
res = Promise.resolve(res) | ||
} | ||
this._dispatching = false | ||
if (!silent) { | ||
const mutation = isObjectStyleDispatch | ||
? payload | ||
: { type, payload } | ||
this._subscribers.forEach(sub => sub(mutation, state)) | ||
} | ||
return res.catch(err => { | ||
console.error(`[vuex] error in Promise returned from action "${type}":`) | ||
console.error(err) | ||
}) | ||
}) | ||
} | ||
commit (type, payload) { | ||
// check object-style commit | ||
let mutation | ||
if (isObject(type) && type.type) { | ||
payload = mutation = type | ||
type = type.type | ||
} else { | ||
console.warn(`[vuex] Unknown mutation: ${type}`) | ||
mutation = { type, payload } | ||
} | ||
const entry = this._mutations[type] | ||
if (!entry) { | ||
console.error(`[vuex] unknown mutation type: ${type}`) | ||
return | ||
} | ||
this._committing = true | ||
entry.forEach(function commitIterator (handler) { | ||
handler(payload) | ||
}) | ||
this._committing = false | ||
if (!payload || !payload.silent) { | ||
this._subscribers.forEach(sub => sub(mutation, this.state)) | ||
} | ||
} | ||
/** | ||
* Watch state changes on the store. | ||
* Same API as Vue's $watch, except when watching a function, | ||
* the function gets the state as the first argument. | ||
* | ||
* @param {Function} fn | ||
* @param {Function} cb | ||
* @param {Object} [options] | ||
*/ | ||
watch (fn, cb, options) { | ||
if (typeof fn !== 'function') { | ||
console.error('Vuex store.watch only accepts function.') | ||
dispatch (type, payload) { | ||
const entry = this._actions[type] | ||
if (!entry) { | ||
debugger | ||
console.error(`[vuex] unknown action type: ${type}`) | ||
return | ||
} | ||
return this._vm.$watch(() => fn(this.state), cb, options) | ||
return entry.length > 1 | ||
? Promise.all(entry.map(handler => handler(payload))) | ||
: entry[0](payload) | ||
} | ||
/** | ||
* Subscribe to state changes. Fires after every mutation. | ||
*/ | ||
subscribe (fn) { | ||
@@ -174,119 +193,109 @@ const subs = this._subscribers | ||
/** | ||
* Hot update mutations & modules. | ||
* | ||
* @param {Object} options | ||
* - {Object} [mutations] | ||
* - {Object} [modules] | ||
*/ | ||
hotUpdate (newOptions) { | ||
this._actions = Object.create(null) | ||
this._mutations = Object.create(null) | ||
const options = this._options | ||
if (newOptions.actions) { | ||
options.actions = newOptions.actions | ||
} | ||
if (newOptions.mutations) { | ||
options.mutations = newOptions.mutations | ||
} | ||
if (newOptions.modules) { | ||
for (const key in newOptions.modules) { | ||
options.modules[key] = newOptions.modules[key] | ||
} | ||
} | ||
this.module([], options, true) | ||
hotUpdate ({ mutations, modules } = {}) { | ||
this._rootMutations = this._mutations = mutations || this._rootMutations | ||
this._setupModuleMutations(modules || this._modules) | ||
// update getters | ||
const getters = extractModuleGetters(newOptions.getters, newOptions.modules) | ||
if (Object.keys(getters).length) { | ||
const oldVm = this._vm | ||
initStoreState(this, this.state, getters) | ||
if (this.strict) { | ||
enableStrictMode(this) | ||
} | ||
// dispatch changes in all subscribed watchers | ||
// to force getter re-evaluation. | ||
this._committing = true | ||
oldVm.state = null | ||
this._committing = false | ||
Vue.nextTick(() => oldVm.$destroy()) | ||
} | ||
} | ||
} | ||
/** | ||
* Attach sub state tree of each module to the root tree. | ||
* | ||
* @param {Object} state | ||
* @param {Object} modules | ||
*/ | ||
_setupModuleState (state, modules) { | ||
if (!isObject(modules)) return | ||
Object.keys(modules).forEach(key => { | ||
const module = modules[key] | ||
// set this module's state | ||
Vue.set(state, key, module.state || {}) | ||
// retrieve nested modules | ||
this._setupModuleState(state[key], module.modules) | ||
function initStoreState (store, state, getters) { | ||
// bind getters | ||
store.getters = {} | ||
const computed = {} | ||
Object.keys(getters).forEach(key => { | ||
const fn = getters[key] | ||
// use computed to leverage its lazy-caching mechanism | ||
computed[key] = () => fn(store._vm.state) | ||
Object.defineProperty(store.getters, key, { | ||
get: () => store._vm[key] | ||
}) | ||
} | ||
}) | ||
/** | ||
* Bind mutations for each module to its sub tree and | ||
* merge them all into one final mutations map. | ||
* | ||
* @param {Object} updatedModules | ||
*/ | ||
// use a Vue instance to store the state tree | ||
// suppress warnings just in case the user has added | ||
// some funky global mixins | ||
const silent = Vue.config.silent | ||
Vue.config.silent = true | ||
store._vm = new Vue({ | ||
data: { state }, | ||
computed | ||
}) | ||
Vue.config.silent = silent | ||
} | ||
_setupModuleMutations (updatedModules) { | ||
const modules = this._modules | ||
Object.keys(updatedModules).forEach(key => { | ||
modules[key] = updatedModules[key] | ||
}) | ||
const updatedMutations = this._createModuleMutations(modules, []) | ||
this._mutations = mergeObjects([this._rootMutations, ...updatedMutations]) | ||
} | ||
/** | ||
* Helper method for _setupModuleMutations. | ||
* The method retrieve nested sub modules and | ||
* bind each mutations to its sub tree recursively. | ||
* | ||
* @param {Object} modules | ||
* @param {Array<String>} nestedKeys | ||
* @return {Array<Object>} | ||
*/ | ||
_createModuleMutations (modules, nestedKeys) { | ||
if (!isObject(modules)) return [] | ||
return Object.keys(modules).map(key => { | ||
const module = modules[key] | ||
const newNestedKeys = nestedKeys.concat(key) | ||
// retrieve nested modules | ||
const nestedMutations = this._createModuleMutations(module.modules, newNestedKeys) | ||
if (!module || !module.mutations) { | ||
return mergeObjects(nestedMutations) | ||
} | ||
// bind mutations to sub state tree | ||
const mutations = {} | ||
Object.keys(module.mutations).forEach(name => { | ||
const original = module.mutations[name] | ||
mutations[name] = (state, ...args) => { | ||
original(getNestedState(state, newNestedKeys), ...args) | ||
function extractModuleGetters (getters = {}, modules = {}, path = []) { | ||
if (!modules) return getters | ||
Object.keys(modules).forEach(key => { | ||
const module = modules[key] | ||
const modulePath = path.concat(key) | ||
if (module.getters) { | ||
Object.keys(module.getters).forEach(getterKey => { | ||
const rawGetter = module.getters[getterKey] | ||
if (getters[getterKey]) { | ||
console.error(`[vuex] duplicate getter key: ${getterKey}`) | ||
return | ||
} | ||
getters[getterKey] = function wrappedGetter (state) { | ||
return rawGetter(getNestedState(state, modulePath)) | ||
} | ||
}) | ||
} | ||
extractModuleGetters(getters, module.modules, modulePath) | ||
}) | ||
return getters | ||
} | ||
// merge mutations of this module and nested modules | ||
return mergeObjects([ | ||
mutations, | ||
...nestedMutations | ||
]) | ||
}) | ||
} | ||
function enableStrictMode (store) { | ||
store._vm.$watch('state', () => { | ||
if (!store._committing) { | ||
throw new Error( | ||
'[vuex] Do not mutate vuex store state outside mutation handlers.' | ||
) | ||
} | ||
}, { deep: true, sync: true }) | ||
} | ||
/** | ||
* Setup mutation check: if the vuex instance's state is mutated | ||
* outside of a mutation handler, we throw en error. This effectively | ||
* enforces all mutations to the state to be trackable and hot-reloadble. | ||
* However, this comes at a run time cost since we are doing a deep | ||
* watch on the entire state tree, so it is only enalbed with the | ||
* strict option is set to true. | ||
*/ | ||
function isObject (obj) { | ||
return obj !== null && typeof obj === 'object' | ||
} | ||
_setupMutationCheck () { | ||
const Watcher = getWatcher(this._vm) | ||
/* eslint-disable no-new */ | ||
new Watcher(this._vm, 'state', () => { | ||
if (!this._dispatching) { | ||
throw new Error( | ||
'[vuex] Do not mutate vuex store state outside mutation handlers.' | ||
) | ||
} | ||
}, { deep: true, sync: true }) | ||
/* eslint-enable no-new */ | ||
} | ||
function isPromise (val) { | ||
return val && typeof val.then === 'function' | ||
} | ||
function getNestedState (state, path) { | ||
return path.reduce((state, key) => state[key], state) | ||
} | ||
function install (_Vue) { | ||
if (Vue) { | ||
console.warn( | ||
console.error( | ||
'[vuex] already installed. Vue.use(Vuex) should be called only once.' | ||
@@ -297,3 +306,3 @@ ) | ||
Vue = _Vue | ||
override(Vue) | ||
applyMixin(Vue) | ||
} | ||
@@ -308,3 +317,5 @@ | ||
Store, | ||
install | ||
install, | ||
mapGetters, | ||
mapActions | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
38532
877
1