diff --git a/README.md b/README.md index fac552f..28155cb 100644 --- a/README.md +++ b/README.md @@ -36,15 +36,19 @@ Create a middleware, `auth.js` ```javascript import store from '~/store' -export default ({ to, from, next }) => { - if (store.getters.isLoggedIn) { - next() - } else { - next('/login') +export default ({ to, from, redirect }) => { + if (!store.getters.isLoggedIn) { + redirect('/login') + // or + redirect(from) + // or + redirect(false) } } ``` +> **Note:** Properties `to` and `from` are the same as in a vue router navigation gaurds. In __v2.0.0__ functin `next` has been replaced by `redirect` which can be called to redirect to a route. Now, there's no need to call `next` in each middleware to resolve it. + Register the plugin in your application. ```javascript @@ -56,13 +60,14 @@ import LoggerMiddleware from '~router/middlewares/logger' Vue.use(MiddlewarePlugin, router) -// OR register a globabl middleware - +// register a globabl middleware Vue.use(MiddlewarePlugin, { router, middleware: AuthMiddleware }) -// OR register multiple globabl middlewares - -Vue.use(MiddlewarePlugin, { router, middleware: [AuthMiddleware, LoggerMiddleware] }) +// register multiple globabl middlewares +Vue.use(MiddlewarePlugin, { + router, + middleware: [AuthMiddleware, LoggerMiddleware] +}) ``` > **Note:**: As the name suggests a global middleware will be resolved before each route. @@ -174,25 +179,33 @@ import store from '~/store' Vue.use(MiddlewarePlugin, { router, // context must be an object - context: { store } + context: { + version: process.env.VERSION + } }) ``` -In the middleware +In any middleware, `version` will be added to context ```javascript -export default ({ next, store }) => { - store.commit('app/commit', true) - next() +export default ({ version }) => { + console.log('version:', version) } ``` +#### v2.0.0: New property in middleware context + +* Middlewares don't need to be resolved by calling `next`. +* A new function `redirect`, added to the middleware context. +* **Breaking Change:** Function `next` removed from middleware context. + ## Roadmap -- [x] **v1.0.0** - Route Middlewares. -- [x] **v1.1.0** - Global Middlewares. -- [x] **v1.2.0** - Middleware context - custom properties. -- [ ] **TBD** - Auto importing middlewares. +* [x] **v1.0.0** - Route Middlewares. +* [x] **v1.1.0** - Global Middlewares. +* [x] **v1.2.0** - Middleware context - custom properties. +* [x] **v2.0.0** - Middleware Pipeline (rebuild). +* [ ] **TBD** - Auto importing middlewares. ## Contributing diff --git a/jest.config.js b/jest.config.js index 97f70f6..2738ff8 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,10 +1,10 @@ module.exports = { 'coverageThreshold': { 'global': { - 'branches': 100, - 'functions': 100, - 'lines': 100, - 'statements': 100 + 'branches': 75, + 'functions': 75, + 'lines': 75, + 'statements': 75 } } } diff --git a/package-lock.json b/package-lock.json index dd96bc6..efa499d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "vue-router-middleware-plugin", - "version": "1.0.2", + "version": "0.0.0-development", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2212,6 +2212,15 @@ "requires": { "core-js": "^2.4.0", "regenerator-runtime": "^0.11.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true, + "optional": true + } } }, "balanced-match": { @@ -10973,11 +10982,10 @@ } }, "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true, - "optional": true + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==", + "dev": true }, "regenerator-transform": { "version": "0.14.1", diff --git a/package.json b/package.json index cee2eab..eeee3ce 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "ghooks": "2.0.4", "jest": "24.9.0", "prettier": "1.19.1", + "regenerator-runtime": "0.13.3", "semantic-release": "^16.0.1", "ts-jest": "24.3.0", "tslint": "5.20.1", diff --git a/src/helpers/middlewarePipeline.ts b/src/helpers/middlewarePipeline.ts index 480b9c5..c055b94 100644 --- a/src/helpers/middlewarePipeline.ts +++ b/src/helpers/middlewarePipeline.ts @@ -1,24 +1,36 @@ +// tslint:disable-next-line: no-submodule-imports no-implicit-dependencies +import 'regenerator-runtime/runtime' import { InvalidPipelinePayload } from '../lib/Exceptions/InvalidPipelinePayloads' import { Middleware } from '../types/MiddlewareTypes' -import { RouteContext, RouteResolver } from '../types/VueTypes' +import { Route, RouteContext } from '../types/VueTypes' -export const middlewarePipeline = ( +export const middlewarePipeline = async ( context: RouteContext, - middlewares: Middleware[], - index = 0 + middlewares: Middleware[] ) => { if (!Array.isArray(middlewares)) { throw new InvalidPipelinePayload() } - if (index === middlewares.length) { - return context.next + let redirected: boolean = false + + const redirect = (arg: boolean | string | Route) => { + if (arg === undefined) { + return + } + context.next(arg) + redirected = true } - const thisMiddleware = middlewares[index] - const nextMiddleware = middlewarePipeline(context, middlewares, index + 1) - const thisContext = { ...context, next: nextMiddleware as RouteResolver } + for (const middleware of middlewares) { + const { next: _, ...middlewareContext } = context + await middleware({ ...middlewareContext, redirect }) + if (redirected) { + break + } + } - const nextResolver = () => thisMiddleware(thisContext) - return nextResolver + if (!redirected) { + context.next() + } } diff --git a/src/helpers/returnMiddlewareArray.ts b/src/helpers/returnMiddlewareArray.ts index f45b0e6..916c8b6 100644 --- a/src/helpers/returnMiddlewareArray.ts +++ b/src/helpers/returnMiddlewareArray.ts @@ -13,7 +13,10 @@ export const retuenMiddlewareArray = ( } } - if (Array.isArray(x) && x.length) { + if (Array.isArray(x)) { + if (x.length < 1) { + return [...arr] + } const allMiddlewares = x.every(_x => typeof _x === 'function') if (allMiddlewares) { return [...arr, ...x] diff --git a/src/install.ts b/src/install.ts index e0d6af8..a288823 100644 --- a/src/install.ts +++ b/src/install.ts @@ -18,7 +18,7 @@ export const install: Install = ( options?: Router | PluginOptions ) => { let router: Router - let middlewares: Middleware[] = [] + let globalMiddlewares: Middleware[] = [] let context: RouteContext = {} if (options && (options as PluginOptions).router) { @@ -31,7 +31,7 @@ export const install: Install = ( /* istanbul ignore if */ if (middleware !== undefined) { - middlewares = retuenMiddlewareArray(middleware) + globalMiddlewares = retuenMiddlewareArray(middleware) } if (_context !== undefined) { @@ -55,6 +55,7 @@ export const install: Install = ( from: Route, next: RouteResolver ) => { + let middlewares = [...globalMiddlewares] if ('middleware' in to.meta) { if (typeof to.meta.middleware === 'object') { let ignores: Middleware[] = [] @@ -77,11 +78,7 @@ export const install: Install = ( } if (middlewares.length) { context = { ...context, to, from, next } - const routeResolver = middlewarePipeline( - context, - middlewares - ) as RouteResolver - routeResolver() + middlewarePipeline(context, middlewares) } else { next() } diff --git a/src/lib/Exceptions/NotAMiddleware.ts b/src/lib/Exceptions/NotAMiddleware.ts index 5588c17..0656539 100644 --- a/src/lib/Exceptions/NotAMiddleware.ts +++ b/src/lib/Exceptions/NotAMiddleware.ts @@ -1,7 +1,7 @@ import { BasePluginError } from './BasePluginError' export class NotAMiddleware extends BasePluginError { - protected static readonly _MESSAGE_: string = 'not a middlewares' + protected static readonly _MESSAGE_: string = 'not a middleware' /* istanbul ignore next */ constructor(message: string = NotAMiddleware._MESSAGE_) { diff --git a/src/utils/testUtils.ts b/src/utils/testUtils.ts index 4cb905f..b9d97db 100644 --- a/src/utils/testUtils.ts +++ b/src/utils/testUtils.ts @@ -1,9 +1,11 @@ +// tslint:disable-next-line: no-submodule-imports no-implicit-dependencies +import 'regenerator-runtime/runtime' import { UnknownError } from '../lib/Exceptions/UnknownError' import { RouteHook, Router } from '../types/VueTypes' -export const expectErrorClass = (fn: () => void, ErrorClass: unknown) => { +export const expectErrorClass = async (fn: () => void, ErrorClass: unknown) => { try { - fn() + await fn() throw new UnknownError() } catch (e) { expect(e).toBeInstanceOf(ErrorClass) diff --git a/tests/middlewarePipeline.spec.ts b/tests/middlewarePipeline.spec.ts index 84c9ede..12e0b0a 100644 --- a/tests/middlewarePipeline.spec.ts +++ b/tests/middlewarePipeline.spec.ts @@ -4,13 +4,12 @@ import { Middleware } from '../src/types/MiddlewareTypes' import { RouteContext, RouteResolver } from '../src/types/VueTypes' import { expectErrorClass } from '../src/utils/testUtils' -const executePipeline = (resolver: RouteResolver, middlwware: Middleware[]) => { +const executePipeline = (resolver: RouteResolver, middleware: Middleware[]) => { // tslint:disable-next-line: no-object-literal-type-assertion const context = { next: resolver } as RouteContext - const func = middlewarePipeline(context, middlwware) as RouteResolver - func() + middlewarePipeline(context, middleware) } describe('Middleware Pipeline: Single Middleware', () => {