diff --git a/package-lock.json b/package-lock.json index 950b5ce0c..f71a0fef8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1349,7 +1349,6 @@ "requires": { "anymatch": "1.3.2", "async-each": "1.0.1", - "fsevents": "1.1.2", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -1359,9 +1358,9 @@ } }, "chromedriver": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-2.31.0.tgz", - "integrity": "sha1-gsdY7kAVqogPRQCLujRkM8+dsUo=", + "version": "2.32.3", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-2.32.3.tgz", + "integrity": "sha1-zoTwVb7ny/5W8xGCsnbzMlaxK/E=", "dev": true, "requires": { "extract-zip": "1.6.5", @@ -1593,9 +1592,9 @@ "dev": true }, "content-type": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz", - "integrity": "sha1-t9ETrueo3Se9IRM8TcJSnfFyHu0=", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", "dev": true }, "convert-source-map": { @@ -2434,9 +2433,9 @@ "dev": true }, "etag": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.0.tgz", - "integrity": "sha1-b2Ma7zNtbEY2K1F2QETOIWvjwFE=", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", "dev": true }, "event-emitter": { @@ -2511,41 +2510,50 @@ } }, "express": { - "version": "4.15.4", - "resolved": "https://registry.npmjs.org/express/-/express-4.15.4.tgz", - "integrity": "sha1-Ay4iU0ic+PzgJma+yj0R7XotrtE=", + "version": "4.15.5", + "resolved": "https://registry.npmjs.org/express/-/express-4.15.5.tgz", + "integrity": "sha1-ZwI1ypWYiQpa6BcLg9tyK4Qu2Sc=", "dev": true, "requires": { "accepts": "1.3.4", "array-flatten": "1.1.1", "content-disposition": "0.5.2", - "content-type": "1.0.2", + "content-type": "1.0.4", "cookie": "0.3.1", "cookie-signature": "1.0.6", - "debug": "2.6.8", + "debug": "2.6.9", "depd": "1.1.1", "encodeurl": "1.0.1", "escape-html": "1.0.3", - "etag": "1.8.0", - "finalhandler": "1.0.4", - "fresh": "0.5.0", + "etag": "1.8.1", + "finalhandler": "1.0.6", + "fresh": "0.5.2", "merge-descriptors": "1.0.1", "methods": "1.1.2", "on-finished": "2.3.0", - "parseurl": "1.3.1", + "parseurl": "1.3.2", "path-to-regexp": "0.1.7", "proxy-addr": "1.1.5", "qs": "6.5.0", "range-parser": "1.2.0", - "send": "0.15.4", - "serve-static": "1.12.4", + "send": "0.15.6", + "serve-static": "1.12.6", "setprototypeof": "1.0.3", "statuses": "1.3.1", "type-is": "1.6.15", "utils-merge": "1.0.0", - "vary": "1.1.1" + "vary": "1.1.2" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, "qs": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.0.tgz", @@ -2686,18 +2694,29 @@ } }, "finalhandler": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.4.tgz", - "integrity": "sha512-16l/r8RgzlXKmFOhZpHBztvye+lAhC5SU7hXavnerC9UfZqZxxXl3BzL8MhffPT3kF61lj9Oav2LKEzh0ei7tg==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.6.tgz", + "integrity": "sha1-AHrqM9Gk0+QgF/YkhIrVjSEvgU8=", "dev": true, "requires": { - "debug": "2.6.8", + "debug": "2.6.9", "encodeurl": "1.0.1", "escape-html": "1.0.3", "on-finished": "2.3.0", - "parseurl": "1.3.1", + "parseurl": "1.3.2", "statuses": "1.3.1", "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } } }, "find-cache-dir": { @@ -2771,15 +2790,15 @@ } }, "forwarded": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz", - "integrity": "sha1-Ge+YdMSuHCl7zweP3mOgm2aoQ2M=", + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", "dev": true }, "fresh": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz", - "integrity": "sha1-9HTKXmqSRtb9jglTz6m5yAWvp44=", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", "dev": true }, "fs-extra": { @@ -5678,9 +5697,9 @@ } }, "parseurl": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz", - "integrity": "sha1-yKuMkiO6NIiKpkopeyiFO+wY2lY=", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", "dev": true }, "path-browserify": { @@ -6468,7 +6487,7 @@ "integrity": "sha1-ccDuOxAt4/IC87ZPYI0XP8uhqRg=", "dev": true, "requires": { - "forwarded": "0.1.0", + "forwarded": "0.1.2", "ipaddr.js": "1.4.0" } }, @@ -7010,6 +7029,12 @@ "rollup-pluginutils": "2.0.1" }, "dependencies": { + "estree-walker": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.3.1.tgz", + "integrity": "sha1-5rGlHPcpJSTnI3wxLl/mZgwc4ao=", + "dev": true + }, "magic-string": { "version": "0.22.4", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.4.tgz", @@ -7018,6 +7043,16 @@ "requires": { "vlq": "0.2.2" } + }, + "rollup-pluginutils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.0.1.tgz", + "integrity": "sha1-fslbNXP2VDpGpkYb2afFRFJdD8A=", + "dev": true, + "requires": { + "estree-walker": "0.3.1", + "micromatch": "2.3.11" + } } } }, @@ -7089,36 +7124,47 @@ "dev": true }, "send": { - "version": "0.15.4", - "resolved": "https://registry.npmjs.org/send/-/send-0.15.4.tgz", - "integrity": "sha1-mF+qPihLAnPHkzZKNcZze9k5Bbk=", + "version": "0.15.6", + "resolved": "https://registry.npmjs.org/send/-/send-0.15.6.tgz", + "integrity": "sha1-IPI6nJJbdiq4JwX+L52yUqzkfjQ=", "dev": true, "requires": { - "debug": "2.6.8", + "debug": "2.6.9", "depd": "1.1.1", "destroy": "1.0.4", "encodeurl": "1.0.1", "escape-html": "1.0.3", - "etag": "1.8.0", - "fresh": "0.5.0", + "etag": "1.8.1", + "fresh": "0.5.2", "http-errors": "1.6.2", "mime": "1.3.4", "ms": "2.0.0", "on-finished": "2.3.0", "range-parser": "1.2.0", "statuses": "1.3.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } } }, "serve-static": { - "version": "1.12.4", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.4.tgz", - "integrity": "sha1-m2qpjutyU8Tu3Ewfb9vKYJkBqWE=", + "version": "1.12.6", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.6.tgz", + "integrity": "sha1-uXN3P2NEmTTaVOW+ul4x2fQhFXc=", "dev": true, "requires": { "encodeurl": "1.0.1", "escape-html": "1.0.3", - "parseurl": "1.3.1", - "send": "0.15.4" + "parseurl": "1.3.2", + "send": "0.15.6" } }, "set-blocking": { @@ -7616,9 +7662,9 @@ "dev": true }, "typescript": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.4.2.tgz", - "integrity": "sha1-+DlfhdRZJ2BnyYiqQYN6j4KHCEQ=", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.3.tgz", + "integrity": "sha512-ptLSQs2S4QuS6/OD1eAKG+S5G8QQtrU5RT32JULdZQtM1L3WTi34Wsu48Yndzi8xsObRAB9RPt/KhA9wlpEF6w==", "dev": true }, "uglify-js": { @@ -7782,9 +7828,9 @@ } }, "vary": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.1.tgz", - "integrity": "sha1-Z1Neu2lMHVIldFeYRmUyP1h+jTc=", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", "dev": true }, "vendors": { @@ -7828,9 +7874,9 @@ } }, "vue": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/vue/-/vue-2.4.3.tgz", - "integrity": "sha512-k6zkIBR0KsE0DLUDGdRLooX/4iRUbc3T2FyrJs4YhVySbjGwS3k5c2HRCHyXo6lg1aeAF9rg3uiJDRz0J7nbDA==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.4.4.tgz", + "integrity": "sha512-PCiRmc8ZT1DD5+BN8QUAmnkBefcCLfZVSuhc1u7iu5JoPrSHyyk/+4nehm7k2xVMi8+RFLk5WIHAN14UKF0txw==", "dev": true }, "vue-hot-reload-api": { @@ -7919,9 +7965,9 @@ } }, "vue-template-compiler": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.4.3.tgz", - "integrity": "sha512-rtHVKIFjd3Ynb+9FSoA64m2h2SPTEVKk6PywkqbugpM0nxT3ykLFyhbLTdSX1qV5wI9h5DAR4ib4RubEFfyiBQ==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.4.4.tgz", + "integrity": "sha512-XdHsNi8Z5WqwuFl/Z5eLKgE2DOEEOdMk1aA459uSgvwyy+pjKLBlQWsUpAtoR6o6Wmpujw6NtinAUGuqSTituQ==", "dev": true, "requires": { "de-indent": "1.0.2", @@ -8018,9 +8064,9 @@ } }, "webpack-hot-middleware": { - "version": "2.18.2", - "resolved": "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.18.2.tgz", - "integrity": "sha512-dB7uOnUWsojZIAC6Nwi5v3tuaQNd2i7p4vF5LsJRyoTOgr2fRYQdMKQxRZIZZaz0cTPBX8rvcWU1A6/n7JTITg==", + "version": "2.19.1", + "resolved": "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.19.1.tgz", + "integrity": "sha512-2x60xmz7XBCNN/Drol+7i85E/5RrNrf+ivOPCgrxhP1F3q3WxpVjjvj8n8fOS1bS9oTRKEDfBYVAtkxqsG7LwQ==", "dev": true, "requires": { "ansi-html": "0.0.7", diff --git a/package.json b/package.json index 99f3f52ac..2b5319ec4 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "babel-plugin-transform-object-rest-spread": "^6.23.0", "babel-polyfill": "^6.22.0", "babel-preset-env": "^1.5.1", - "chromedriver": "^2.27.2", + "chromedriver": "^2.32.3", "cross-spawn": "^5.0.1", "css-loader": "^0.28.7", "eslint": "^3.19.0", @@ -72,6 +72,6 @@ "vue-template-compiler": "^2.4.3", "webpack": "^3.6.0", "webpack-dev-middleware": "^1.10.0", - "webpack-hot-middleware": "^2.16.1" + "webpack-hot-middleware": "^2.19.1" } } diff --git a/src/module/module-collection.js b/src/module/module-collection.js index 910c6d2c6..a68f05a51 100644 --- a/src/module/module-collection.js +++ b/src/module/module-collection.js @@ -84,25 +84,43 @@ function update (path, targetModule, newModule) { } } +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) { - ['getters', 'actions', 'mutations'].forEach(key => { + Object.keys(assertTypes).forEach(key => { if (!rawModule[key]) return + const assertOptions = assertTypes[key] + forEachValue(rawModule[key], (value, type) => { assert( - typeof value === 'function', - makeAssertionMessage(path, key, type, value) + assertOptions.assert(value), + makeAssertionMessage(path, key, type, value, assertOptions.expected) ) }) }) } -function makeAssertionMessage (path, key, type, value) { - let buf = `${key} should be function but "${key}.${type}"` +function makeAssertionMessage (path, key, type, value, 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 } diff --git a/src/store.js b/src/store.js index 8630b9e68..65ca98567 100644 --- a/src/store.js +++ b/src/store.js @@ -287,8 +287,9 @@ function installModule (store, rootState, path, module, hot) { }) module.forEachAction((action, key) => { - const namespacedType = namespace + key - registerAction(store, namespacedType, action, local) + const type = action.root ? key : namespace + key + const handler = action.handler || action + registerAction(store, type, handler, local) }) module.forEachGetter((getter, key) => { diff --git a/test/unit/modules.spec.js b/test/unit/modules.spec.js index a778ac3f2..6ede57405 100644 --- a/test/unit/modules.spec.js +++ b/test/unit/modules.spec.js @@ -573,6 +573,61 @@ describe('Modules', () => { }) }) + it('root actions dispatched in namespaced modules', done => { + const store = new Vuex.Store({ + modules: { + a: { + namespaced: true, + actions: { + [TEST]: { + root: true, + handler () { + return 1 + } + } + } + }, + b: { + namespaced: true, + actions: { + [TEST]: { + root: true, + handler () { + return new Promise(r => r(2)) + } + } + } + }, + c: { + namespaced: true, + actions: { + [TEST]: { + handler () { + // Should not be called + return 3 + } + } + } + }, + d: { + namespaced: true, + actions: { + [TEST] () { + // Should not be called + return 4 + } + } + } + } + }) + store.dispatch(TEST).then(res => { + expect(res.length).toBe(2) + expect(res[0]).toBe(1) + expect(res[1]).toBe(2) + done() + }) + }) + it('plugins', function () { let initState const mutations = [] @@ -641,7 +696,7 @@ describe('Modules', () => { } }) }).toThrowError( - /actions should be function but "actions\.test" is "test"/ + /actions should be function or object with "handler" function but "actions\.test" is "test"/ ) expect(() => { @@ -659,7 +714,7 @@ describe('Modules', () => { } }) }).toThrowError( - /actions should be function but "actions\.test" in module "foo\.bar" is "error"/ + /actions should be function or object with "handler" function but "actions\.test" in module "foo\.bar" is "error"/ ) }) diff --git a/types/index.d.ts b/types/index.d.ts index f1fa8514f..75ac9d31e 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -82,8 +82,14 @@ export interface StoreOptions { strict?: boolean; } +type ActionHandler = (injectee: ActionContext, payload: any) => any; +interface ActionObject { + root?: boolean; + handler: ActionHandler; +} + export type Getter = (state: S, getters: any, rootState: R, rootGetters: any) => any; -export type Action = (injectee: ActionContext, payload: any) => any; +export type Action = ActionHandler | ActionObject; export type Mutation = (state: S, payload: any) => any; export type Plugin = (store: Store) => any; diff --git a/types/test/index.ts b/types/test/index.ts index 95c73884f..7b66559d0 100644 --- a/types/test/index.ts +++ b/types/test/index.ts @@ -138,6 +138,19 @@ namespace NamespacedModule { a: { namespaced: true, state: { value: 1 }, + actions: { + test: { + root: true, + handler ({ dispatch }) { + dispatch('foo') + } + }, + test2: { + handler ({ dispatch }) { + dispatch('foo') + } + } + }, modules: { b: { state: { value: 2 }