install
if(!Vue && typeof window !== 'undefined' && window.Vue){
install(window.Vue)
}
install
function install(_Vue){
if(Vue && _Vue === Vue){
if(__DEV__){
console.error(`[vuex] already installed. Vue.use(Vuex) should be called only once`)
}
return
}
Vue = _Vue
applyMixin(Vue)
}
applyMixin
export default function(Vue){
const version = Number(Vue.version.split('.')[0])
if(version >= 2){
Vue.mixin({beforeCreate:vuexInit})
}else{
const _init = Vue.prototype._init
Vue.prototype._init = function(options = {}){
options.init = options.init ? [vuexInit].concat(options.init) : vuexInit
_init.call(this,options)
}
}
}
function vuexInit(){
const options = this.$options
if(options.store){
this.$store = typeof options.store === 'function' ? options.store() : options.store
}else if(options.parent && options.parent.$store){
this.$store = options.parent.$store
}
}
modules
this._modules = new ModuleCollection(options)
ModuleCollection
class ModuleCollection{
constructor(rawRootModule){
this.register([],rawRootModule,false)
}
get(path){
return path.reduce((module,key) =>{
return module.getChild(key)
},this.root)
}
getNamespace(path){
let module = this.root
return path.reduce((namespace,key) =>{
module = module.getChild(key)
return namespace + (module.namespaced ? key + '/' : '')
},'')
}
update(rawRootModule){
update([],this.root,rawRootModule)
}
register(path,rawModule,runtime = true){
if(__DEV__){
assertRawModule(path,rawModule)
}
const newModule = new Module(rawModule,runtime)
if(path.length === 0){
this.root = newModule
}else{
const parent = this.get(path.lice(0,-1))
parent.addChild(path[path.length - 1],newModule)
}
if(rawModule.modules){
forEachValue(rawModule.modules,(rawChildModule,key) => {
this.register(path.concat[key],rawChildModule,runtime)
})
}
}
unregister(path){
const parent = this.get(path.slice(0,-1))
const key = path[path.length - 1]
const child = parent.getChild(key)
if(!child){
if(__DEV__){
console.warn(`[vuex] tring to unregister module '${key}', which is not registerd`)
}
return
}
if(!child.runtime){
return
}
parent.removeChild(key)
}
isRegistered(path){
const parent = this.get(path.slice(0,-1))
const key = path[path.length - 1]
if(parent){
return parent.hasChild(key)
}
return false
}
}
assertRawModule
const functionAssert = {
assert: value => typeof value === 'function',
expected:'function'
}
const objectAssert = {
assert:value => typeof value === 'function' || (typeof value === 'object' && typeof value.handler === 'function'),
expected:'function or object with "handler" function'
}
const assertTypes = {
getters:functionAssert,
mutations:functionAssert,
actions:objectAssert
}
function assertRawModule(path,rawModule){
Object.keys(assertTypes).forEach(key => {
if(!rawModule[key]) return
const assertOptions = assertTypes[key]
forEachValue(rawModule[key],(value,type) => {
assert(assertOptions.assert(value),makeAssertionMessage(path,key,type,value,assertOptions.expected))
})
})
}
function makeAssertionMessage(path,key,type,value,assertOptions.expected){
let buf = `${key} should be ${expected} but "${key}.${type}"`
if(path.length > 0){
buf += `in module "${path.join('.')}"`
}
buf += ` is ${JSON.stringify(value)}`
return buf
}
update
function update(path,targetModule,newMoudle){
if(__DEV__){
assertRawMoudle(path,newModule)
}
targetMoudle.update(newModule)
if(newModule.modules){
for(const key in newModule.modules){
if(!targetModule.getChild(key)){
if(__DEV__){
console.warn(`[vuex] trying to add a new module '${key}' on hot reloading, manual reload is needed`)
}
return
}
update(path.concat(key),targetModule.getChild(key),newModule.modules[key])
}
}
}
Module
class Module{
constructor(rawModule,runtime){
this.runtime = runtime
this._children = Object.create(null)
this._rawModule = rawModule
const rawState = rawModule.state
this.state = (typeof rawState === 'function' ? rawState() : rawState) || {}
}
get namespaced(){
return !!this._rawModule.namespaced
}
addChild(key,module){
this._children[key] = module
}
removeChild(key){
delete this._children[key]
}
getChild(key){
return this._children[key]
}
hasChild(key){
return key in this._children
}
update(rawModule){
this._rawModule.namspaced = rawModule.namespaced
if(rawModule.actions){
this._rawModule.actions = rawModule.actions
}
if(rawModule.mutations){
this._rawModule.mutations = rawModule.mutations
}
if(rawModule.getters){
this._rawModule.getters = rawModule.getters
}
}
forEachChild(fn){
forEachValue(this._children,fn)
}
forEachGetter(fn){
if(this._rawModule.getters){
forEachValue(this._rawModule.getters,fn)
}
}
forEachAction(fn){
if(this._rawModule.actions){
forEachValue(this._rawModule.actions,fn)
}
}
forEachMutation(fn){
if(this._rawModule.mutations){
forEachValue(this._rawMoudle.mutations,fn)
}
}
}