/** * Module dependencies. */ const debug = require('debug')('koa-mount') const compose = require('koa-compose') const assert = require('assert') /** * Expose `mount()`. */ module.exports = mount /** * Mount `app` with `prefix`, `app` * may be a Koa application or * middleware function. * * @param {String|Application|Function} prefix, app, or function * @param {Application|Function} [app or function] * @return {Function} * @api public */ function mount (prefix, app) { if (typeof prefix !== 'string') { app = prefix prefix = '/' } assert.equal(prefix[0], '/', 'mount path must begin with "/"') // compose const downstream = app.middleware ? compose(app.middleware) : app // don't need to do mounting here if (prefix === '/') return downstream const trailingSlash = prefix.slice(-1) === '/' const name = app.name || 'unnamed' debug('mount %s %s', prefix, name) return async function (ctx, upstream) { const prev = ctx.path const newPath = match(prev) debug('mount %s %s -> %s', prefix, name, newPath) if (!newPath) return await upstream() ctx.mountPath = prefix ctx.path = newPath debug('enter %s -> %s', prev, ctx.path) await downstream(ctx, async () => { ctx.path = prev await upstream() ctx.path = newPath }) debug('leave %s -> %s', prev, ctx.path) ctx.path = prev } /** * Check if `prefix` satisfies a `path`. * Returns the new path. * * match('/images/', '/lkajsldkjf') => false * match('/images', '/images') => / * match('/images/', '/images') => false * match('/images/', '/images/asdf') => /asdf * * @param {String} prefix * @param {String} path * @return {String|Boolean} * @api private */ function match (path) { // does not match prefix at all if (path.indexOf(prefix) !== 0) return false const newPath = path.replace(prefix, '') || '/' if (trailingSlash) return newPath // `/mount` does not match `/mountlkjalskjdf` if (newPath[0] !== '/') return false return newPath } }