Remove koa-compose as as it can just be included in koa
This commit is contained in:
parent
d655f208cb
commit
8157e9e752
4 changed files with 407 additions and 2 deletions
|
@ -8,7 +8,7 @@
|
||||||
const debug = require('debug-ms')('koa:application');
|
const debug = require('debug-ms')('koa:application');
|
||||||
const onFinished = require('./onfinish');
|
const onFinished = require('./onfinish');
|
||||||
const response = require('./response');
|
const response = require('./response');
|
||||||
const compose = require('koa-compose');
|
const compose = require('./compose');
|
||||||
const isJSON = require('./isjson');
|
const isJSON = require('./isjson');
|
||||||
const context = require('./context');
|
const context = require('./context');
|
||||||
const request = require('./request');
|
const request = require('./request');
|
||||||
|
|
52
lib/compose.js
Normal file
52
lib/compose.js
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/**
|
||||||
|
* Lifted from koa-compose package.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compose `middleware` returning
|
||||||
|
* a fully valid middleware comprised
|
||||||
|
* of all those which are passed.
|
||||||
|
*
|
||||||
|
* @param {Array} middleware
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function compose(middleware) {
|
||||||
|
if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!');
|
||||||
|
for (const fn of middleware) {
|
||||||
|
if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} context
|
||||||
|
* @return {Promise}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
return function(context, next) {
|
||||||
|
// last called middleware #
|
||||||
|
let index = -1;
|
||||||
|
return dispatch(0);
|
||||||
|
function dispatch(i) {
|
||||||
|
if (i <= index) return Promise.reject(new Error('next() called multiple times'));
|
||||||
|
index = i;
|
||||||
|
let fn = middleware[i];
|
||||||
|
if (i === middleware.length) fn = next;
|
||||||
|
if (!fn) return Promise.resolve();
|
||||||
|
try {
|
||||||
|
return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
|
||||||
|
} catch (err) {
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose compositor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = compose;
|
|
@ -26,7 +26,6 @@
|
||||||
"debug-ms": "~4.1.2",
|
"debug-ms": "~4.1.2",
|
||||||
"fresh": "~0.5.2",
|
"fresh": "~0.5.2",
|
||||||
"http-errors-lite": "^2.0.2",
|
"http-errors-lite": "^2.0.2",
|
||||||
"koa-compose": "^4.1.0",
|
|
||||||
"type-is": "^1.6.16"
|
"type-is": "^1.6.16"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
354
test/utils/compose.js
Normal file
354
test/utils/compose.js
Normal file
|
@ -0,0 +1,354 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/* eslint-env jest */
|
||||||
|
|
||||||
|
const compose = require('../../lib/compose');
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
|
function wait(ms){
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms || 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPromise(x){
|
||||||
|
return x && typeof x.then === 'function';
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Koa Compose', () => {
|
||||||
|
it('should work', async() => {
|
||||||
|
const arr = [];
|
||||||
|
const stack = [];
|
||||||
|
|
||||||
|
stack.push(async(context, next) => {
|
||||||
|
arr.push(1);
|
||||||
|
await wait(1);
|
||||||
|
await next();
|
||||||
|
await wait(1);
|
||||||
|
arr.push(6);
|
||||||
|
});
|
||||||
|
|
||||||
|
stack.push(async(context, next) => {
|
||||||
|
arr.push(2);
|
||||||
|
await wait(1);
|
||||||
|
await next();
|
||||||
|
await wait(1);
|
||||||
|
arr.push(5);
|
||||||
|
});
|
||||||
|
|
||||||
|
stack.push(async(context, next) => {
|
||||||
|
arr.push(3);
|
||||||
|
await wait(1);
|
||||||
|
await next();
|
||||||
|
await wait(1);
|
||||||
|
arr.push(4);
|
||||||
|
});
|
||||||
|
|
||||||
|
await compose(stack)({});
|
||||||
|
assert.deepEqual(arr, [1, 2, 3, 4, 5, 6]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to be called twice', () => {
|
||||||
|
let stack = [];
|
||||||
|
|
||||||
|
stack.push(async(context, next) => {
|
||||||
|
context.arr.push(1);
|
||||||
|
await wait(1);
|
||||||
|
await next();
|
||||||
|
await wait(1);
|
||||||
|
context.arr.push(6);
|
||||||
|
});
|
||||||
|
|
||||||
|
stack.push(async(context, next) => {
|
||||||
|
context.arr.push(2);
|
||||||
|
await wait(1);
|
||||||
|
await next();
|
||||||
|
await wait(1);
|
||||||
|
context.arr.push(5);
|
||||||
|
});
|
||||||
|
|
||||||
|
stack.push(async(context, next) => {
|
||||||
|
context.arr.push(3);
|
||||||
|
await wait(1);
|
||||||
|
await next();
|
||||||
|
await wait(1);
|
||||||
|
context.arr.push(4);
|
||||||
|
});
|
||||||
|
|
||||||
|
const fn = compose(stack);
|
||||||
|
const ctx1 = { arr: [] };
|
||||||
|
const ctx2 = { arr: [] };
|
||||||
|
const out = [1, 2, 3, 4, 5, 6];
|
||||||
|
|
||||||
|
return fn(ctx1).then(() => {
|
||||||
|
assert.deepEqual(out, ctx1.arr);
|
||||||
|
return fn(ctx2);
|
||||||
|
}).then(() => {
|
||||||
|
assert.deepEqual(out, ctx2.arr);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should only accept an array', () => {
|
||||||
|
let err;
|
||||||
|
try {
|
||||||
|
compose();
|
||||||
|
throw new Error('should not be called');
|
||||||
|
} catch (e) {
|
||||||
|
err = e;
|
||||||
|
}
|
||||||
|
return assert(err instanceof TypeError);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create next functions that return a Promise', () => {
|
||||||
|
const stack = [];
|
||||||
|
const arr = [];
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
stack.push((context, next) => {
|
||||||
|
arr.push(next());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
compose(stack)({});
|
||||||
|
|
||||||
|
for (let next of arr) {
|
||||||
|
assert(isPromise(next), 'one of the functions next is not a Promise');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should work with 0 middleware', () => {
|
||||||
|
return compose([])({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should only accept middleware as functions', () => {
|
||||||
|
let err;
|
||||||
|
try {
|
||||||
|
compose([{}]);
|
||||||
|
throw new Error('should not be called');
|
||||||
|
} catch (e) {
|
||||||
|
err = e;
|
||||||
|
}
|
||||||
|
return assert(err instanceof TypeError);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should work when yielding at the end of the stack', async() => {
|
||||||
|
let stack = [];
|
||||||
|
let called = false;
|
||||||
|
|
||||||
|
stack.push(async(ctx, next) => {
|
||||||
|
await next();
|
||||||
|
called = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
await compose(stack)({});
|
||||||
|
assert(called);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reject on errors in middleware', () => {
|
||||||
|
let stack = [];
|
||||||
|
|
||||||
|
stack.push(() => { throw new Error(); });
|
||||||
|
|
||||||
|
return compose(stack)({})
|
||||||
|
.then(() => {
|
||||||
|
throw new Error('promise was not rejected');
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
assert(e instanceof Error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should work when yielding at the end of the stack with yield*', () => {
|
||||||
|
let stack = [];
|
||||||
|
|
||||||
|
stack.push(async(ctx, next) => {
|
||||||
|
await next;
|
||||||
|
});
|
||||||
|
|
||||||
|
return compose(stack)({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should keep the context', () => {
|
||||||
|
const ctx = {};
|
||||||
|
|
||||||
|
const stack = [];
|
||||||
|
|
||||||
|
stack.push(async(ctx2, next) => {
|
||||||
|
await next();
|
||||||
|
assert.strictEqual(ctx2, ctx);
|
||||||
|
});
|
||||||
|
|
||||||
|
stack.push(async(ctx2, next) => {
|
||||||
|
await next();
|
||||||
|
assert.strictEqual(ctx2, ctx);
|
||||||
|
});
|
||||||
|
|
||||||
|
stack.push(async(ctx2, next) => {
|
||||||
|
await next();
|
||||||
|
assert.strictEqual(ctx2, ctx);
|
||||||
|
});
|
||||||
|
|
||||||
|
return compose(stack)(ctx);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should catch downstream errors', async() => {
|
||||||
|
const arr = [];
|
||||||
|
const stack = [];
|
||||||
|
|
||||||
|
stack.push(async(ctx, next) => {
|
||||||
|
arr.push(1);
|
||||||
|
try {
|
||||||
|
arr.push(6);
|
||||||
|
await next();
|
||||||
|
arr.push(7);
|
||||||
|
} catch (err) {
|
||||||
|
arr.push(2);
|
||||||
|
}
|
||||||
|
arr.push(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
stack.push(async(ctx, next) => {
|
||||||
|
arr.push(4);
|
||||||
|
throw new Error();
|
||||||
|
});
|
||||||
|
|
||||||
|
await compose(stack)({});
|
||||||
|
assert.deepEqual(arr, [1, 6, 4, 2, 3]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should compose w/ next', () => {
|
||||||
|
let called = false;
|
||||||
|
|
||||||
|
return compose([])({}, async() => {
|
||||||
|
called = true;
|
||||||
|
}).then(() => {
|
||||||
|
assert(called);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle errors in wrapped non-async functions', () => {
|
||||||
|
const stack = [];
|
||||||
|
|
||||||
|
stack.push(() => {
|
||||||
|
throw new Error();
|
||||||
|
});
|
||||||
|
|
||||||
|
return compose(stack)({}).then(() => {
|
||||||
|
throw new Error('promise was not rejected');
|
||||||
|
}).catch(e => {
|
||||||
|
assert(e instanceof Error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// https://github.com/koajs/compose/pull/27#issuecomment-143109739
|
||||||
|
it('should compose w/ other compositions', () => {
|
||||||
|
let called = [];
|
||||||
|
|
||||||
|
return compose([
|
||||||
|
compose([
|
||||||
|
(ctx, next) => {
|
||||||
|
called.push(1);
|
||||||
|
return next();
|
||||||
|
},
|
||||||
|
(ctx, next) => {
|
||||||
|
called.push(2);
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
]),
|
||||||
|
(ctx, next) => {
|
||||||
|
called.push(3);
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
])({}).then(() => assert.deepEqual(called, [1, 2, 3]));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw if next() is called multiple times', () => {
|
||||||
|
return compose([
|
||||||
|
async(ctx, next) => {
|
||||||
|
await next();
|
||||||
|
await next();
|
||||||
|
}
|
||||||
|
])({}).then(() => {
|
||||||
|
throw new Error('boom');
|
||||||
|
}, err => {
|
||||||
|
assert(/multiple times/.test(err.message));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a valid middleware', () => {
|
||||||
|
let val = 0;
|
||||||
|
return compose([
|
||||||
|
compose([
|
||||||
|
(ctx, next) => {
|
||||||
|
val++;
|
||||||
|
return next();
|
||||||
|
},
|
||||||
|
(ctx, next) => {
|
||||||
|
val++;
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
]),
|
||||||
|
(ctx, next) => {
|
||||||
|
val++;
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
])({}).then(() => {
|
||||||
|
assert.strictEqual(val, 3);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return last return value', () => {
|
||||||
|
const stack = [];
|
||||||
|
|
||||||
|
stack.push(async(context, next) => {
|
||||||
|
let val = await next();
|
||||||
|
assert.strictEqual(val, 2);
|
||||||
|
return 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
stack.push(async(context, next) => {
|
||||||
|
const val = await next();
|
||||||
|
assert.strictEqual(val, 0);
|
||||||
|
return 2;
|
||||||
|
});
|
||||||
|
|
||||||
|
const next = () => 0;
|
||||||
|
return compose(stack)({}, next).then(val => {
|
||||||
|
assert.strictEqual(val, 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not affect the original middleware array', () => {
|
||||||
|
const middleware = [];
|
||||||
|
const fn1 = (ctx, next) => {
|
||||||
|
return next();
|
||||||
|
};
|
||||||
|
middleware.push(fn1);
|
||||||
|
|
||||||
|
for (const fn of middleware) {
|
||||||
|
assert.equal(fn, fn1);
|
||||||
|
}
|
||||||
|
|
||||||
|
compose(middleware);
|
||||||
|
|
||||||
|
for (const fn of middleware) {
|
||||||
|
assert.equal(fn, fn1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not get stuck on the passed in next', () => {
|
||||||
|
const middleware = [(ctx, next) => {
|
||||||
|
ctx.middleware++;
|
||||||
|
return next();
|
||||||
|
}];
|
||||||
|
const ctx = {
|
||||||
|
middleware: 0,
|
||||||
|
next: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
return compose(middleware)(ctx, (ctx, next) => {
|
||||||
|
ctx.next++;
|
||||||
|
return next();
|
||||||
|
}).then(() => {
|
||||||
|
assert.strictEqual(ctx.middleware, 1);
|
||||||
|
assert.strictEqual(ctx.next, 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue