koa-convert
Advanced tools
Comparing version 0.0.2 to 1.0.0
38
index.js
@@ -1,23 +0,33 @@ | ||
'use strict'; | ||
'use strict' | ||
const co = require('co') | ||
const compose = require('koa-compose') | ||
module.exports = convert | ||
function convert(mw) { | ||
if (typeof mw !== 'function') { | ||
throw new TypeError(mw + ' is not function') | ||
function convert (mw) { | ||
if (typeof mw !== 'function') { | ||
throw new TypeError('middleware must be a function') | ||
} | ||
if (mw.constructor.name === 'GeneratorFunction') { | ||
return function (ctx, next) { | ||
return co.call(ctx, mw.call(ctx, createGenerator(next))) | ||
} | ||
if (mw.constructor.name === 'GeneratorFunction') { | ||
return function (ctx, next) { | ||
return co.call(ctx, mw.call(ctx, createGenerator(next))) | ||
} | ||
} else { | ||
// assume it's Promise-based middleware | ||
return mw | ||
} | ||
} else { | ||
// assume it's Promise-based middleware | ||
return mw | ||
} | ||
} | ||
function* createGenerator(next) { | ||
return yield next() | ||
// convert.compose(mw, mw, mw) | ||
// convert.compose([mw, mw, mw]) | ||
convert.compose = function (arr) { | ||
if (!Array.isArray(arr)) { | ||
arr = Array.from(arguments) | ||
} | ||
return compose(arr.map(convert)) | ||
} | ||
function * createGenerator (next) { | ||
return yield next() | ||
} |
{ | ||
"name": "koa-convert", | ||
"version": "0.0.2", | ||
"version": "1.0.0", | ||
"keywords": [ | ||
@@ -9,7 +9,3 @@ "koa", | ||
], | ||
"description": "convert koa generator-based middleware to promise-based middleware", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "mocha test.js" | ||
}, | ||
"description": "convert koa legacy generator-based middleware to promise-based middleware", | ||
"repository": { | ||
@@ -19,2 +15,6 @@ "type": "git", | ||
}, | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "standard && mocha test.js" | ||
}, | ||
"author": "gyson <eilian.yunsong@gmail.com>", | ||
@@ -27,7 +27,14 @@ "license": "MIT", | ||
"dependencies": { | ||
"co": "^4.6.0" | ||
"co": "^4.6.0", | ||
"koa-compose": "^3.0.0" | ||
}, | ||
"devDependencies": { | ||
"mocha": "^2.3.3" | ||
"koa": "^2.0.0-alpha.2", | ||
"mocha": "^2.3.3", | ||
"standard": "^5.3.1", | ||
"supertest": "^1.1.0" | ||
}, | ||
"engines": { | ||
"node": ">= 4" | ||
} | ||
} |
130
README.md
# koa-convert | ||
Convert koa generator-based middleware to promise-based middleware. | ||
[![npm version](https://img.shields.io/npm/v/koa-convert.svg)](https://npmjs.org/package/koa-convert) | ||
[![build status](https://travis-ci.org/gyson/koa-convert.svg)](https://travis-ci.org/gyson/koa-convert) | ||
Convert koa legacy ( 0.x & 1.x ) generator middleware to modern promise middleware ( 2.x ). | ||
## Installation | ||
@@ -12,46 +15,105 @@ | ||
## Related Issues | ||
## Usage | ||
* koa [#415](https://github.com/koajs/koa/issues/415) | ||
* koa-compose [#27](https://github.com/koajs/compose/pull/27) | ||
```js | ||
const Koa = require('koa') // koa v2.x | ||
const convert = require('koa-convert') | ||
const app = new Koa() | ||
## Usage | ||
app.use(modernMiddleware) | ||
app.use(convert(legacyMiddleware)) | ||
app.use(convert.compose(legacyMiddleware, modernMiddleware)) | ||
function * legacyMiddleware (next) { | ||
// before | ||
yield next | ||
// after | ||
} | ||
function modernMiddleware (ctx, next) { | ||
// before | ||
return next().then(() => { | ||
// after | ||
}) | ||
} | ||
``` | ||
## Distinguish legacy and modern middleware | ||
In koa 0.x and 1.x ( without experimental flag ), `app.use` has an assertion that all ( legacy ) middleware must be generator function and it's tested with `fn.constructor.name == 'GeneratorFunction'` at [here](https://github.com/koajs/koa/blob/7fe29d92f1e826d9ce36029e1b9263b94cba8a7c/lib/application.js#L105). | ||
Therefore, we can distinguish legacy and modern middleware with `fn.constructor.name == 'GeneratorFunction'`. | ||
## Migration | ||
`app.use(legacyMiddleware)` is everywhere in 0.x and 1.x and it would be painful to manually change all of them to `app.use(convert(legacyMiddleware))`. | ||
You can use following snippet to make migration easier. | ||
```js | ||
const _use = app.use | ||
app.use = x => _use.call(app, convert(x)) | ||
``` | ||
The above snippet will override `app.use` method and implicitly convert all legacy generator middleware to modern promise middleware. | ||
Therefore, you can have both `app.use(modernMiddleware)` and `app.use(legacyMiddleware)` and your 0.x or 1.x should work without modification. | ||
Complete example: | ||
```js | ||
const Koa = require('koa') // v2.x | ||
const convert = require('koa-convert') | ||
const app = new Koa() | ||
// | ||
// convert a generator-based middleware to promise-based middleware | ||
// | ||
let promiseBased = convert(function* generatorBased(next) { | ||
yield next | ||
// or | ||
// yield* next | ||
}) | ||
// ---------- override app.use method ---------- | ||
// | ||
// convert array of middleware | ||
// | ||
let mws = [ | ||
// will convert it to promise-based middleware | ||
function* generatorMW (next) { | ||
yield next | ||
}, | ||
// will convert it to promise-based middleware | ||
function* generatorMW(next) { | ||
yield* next | ||
}, | ||
// return itself if it's not generator-based middleware | ||
function (ctx, next) { | ||
return next() | ||
}, | ||
// return itself if it's not generator-based middleware | ||
async function (ctx, next) { | ||
await next() | ||
}, | ||
].map(convert) | ||
const _use = app.use | ||
app.use = x => _use.call(app, convert(x)) | ||
// ---------- end ---------- | ||
app.use(modernMiddleware) | ||
// this will be converted to modern promise middleware implicitly | ||
app.use(legacyMiddleware) | ||
function * legacyMiddleware (next) { | ||
// before | ||
yield next | ||
// after | ||
} | ||
function modernMiddleware (ctx, next) { | ||
// before | ||
return next().then(() => { | ||
// after | ||
}) | ||
} | ||
``` | ||
## API | ||
#### `convert()` | ||
Convert legacy generator middleware to modern promise middleware | ||
```js | ||
app.use(convert(legacyMiddleware)) | ||
``` | ||
#### `convert.compose()` | ||
Convert and compose multiple middleware (could mix legacy and modern ones) and return modern promise middleware | ||
```js | ||
app.use(convert.compose(legacyMiddleware, modernMiddleware)) | ||
// or | ||
app.use(convert.compose([legacyMiddleware, modernMiddleware])) | ||
``` | ||
## License | ||
MIT |
218
test.js
@@ -1,61 +0,189 @@ | ||
'use strict'; | ||
/* global describe, it */ | ||
'use strict' | ||
const co = require('co') | ||
const Koa = require('koa') | ||
const assert = require('assert') | ||
const convert = require('./index') | ||
const request = require('supertest') | ||
describe('Koa Convert', function () { | ||
it('should works', function (done) { | ||
let call = [] | ||
let ctx = {} | ||
let mw = convert(function* (next) { | ||
assert.ok(ctx === this) | ||
call.push(1) | ||
}) | ||
describe('convert()', () => { | ||
it('should work', () => { | ||
let call = [] | ||
let ctx = {} | ||
let mw = convert(function * (next) { | ||
assert.ok(ctx === this) | ||
call.push(1) | ||
}) | ||
mw(ctx, function () { | ||
done(new Error('this should not be called')) | ||
}).then(function () { | ||
assert.deepEqual(call, [1]) | ||
done() | ||
}) | ||
return mw(ctx, function () { | ||
call.push(2) | ||
}).then(function () { | ||
assert.deepEqual(call, [1]) | ||
}) | ||
}) | ||
it('should works with `yield next`', function (done) { | ||
let call = [] | ||
let ctx = {} | ||
let mw = convert(function* (next) { | ||
assert.ok(ctx === this) | ||
call.push(1) | ||
yield next | ||
call.push(3) | ||
it('should work with `yield next`', () => { | ||
let call = [] | ||
let ctx = {} | ||
let mw = convert(function * (next) { | ||
assert.ok(ctx === this) | ||
call.push(1) | ||
yield next | ||
call.push(3) | ||
}) | ||
return mw(ctx, function () { | ||
call.push(2) | ||
return Promise.resolve() | ||
}).then(function () { | ||
assert.deepEqual(call, [1, 2, 3]) | ||
}) | ||
}) | ||
it('should work with `yield* next`', () => { | ||
let call = [] | ||
let ctx = {} | ||
let mw = convert(function * (next) { | ||
assert.ok(ctx === this) | ||
call.push(1) | ||
yield* next | ||
call.push(3) | ||
}) | ||
return mw(ctx, function () { | ||
call.push(2) | ||
return Promise.resolve() | ||
}).then(function () { | ||
assert.deepEqual(call, [1, 2, 3]) | ||
}) | ||
}) | ||
}) | ||
describe('convert.compose()', () => { | ||
it('should work', () => { | ||
let call = [] | ||
let context = {} | ||
let _context | ||
let mw = convert.compose([ | ||
function * name (next) { | ||
call.push(1) | ||
yield next | ||
call.push(11) | ||
}, | ||
(ctx, next) => { | ||
call.push(2) | ||
return next().then(() => { | ||
call.push(10) | ||
}) | ||
}, | ||
function * (next) { | ||
call.push(3) | ||
yield* next | ||
call.push(9) | ||
}, | ||
co.wrap(function * (ctx, next) { | ||
call.push(4) | ||
yield next() | ||
call.push(8) | ||
}), | ||
function * (next) { | ||
try { | ||
call.push(5) | ||
yield next | ||
} catch (e) { | ||
call.push(7) | ||
} | ||
}, | ||
(ctx, next) => { | ||
_context = ctx | ||
call.push(6) | ||
throw new Error() | ||
} | ||
]) | ||
mw(ctx, function () { | ||
call.push(2) | ||
return Promise.resolve() | ||
}).then(function () { | ||
assert.deepEqual(call, [1, 2, 3]) | ||
done() | ||
}) | ||
return mw(context).then(() => { | ||
assert.equal(context, _context) | ||
assert.deepEqual(call, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) | ||
}) | ||
}) | ||
it('should works with `yield* next`', function (done) { | ||
let call = [] | ||
let ctx = {} | ||
let mw = convert(function* (next) { | ||
assert.ok(ctx === this) | ||
call.push(1) | ||
yield* next | ||
call.push(3) | ||
it('should work too', () => { | ||
let call = [] | ||
let context = {} | ||
let _context | ||
let mw = convert.compose( | ||
(ctx, next) => { | ||
call.push(1) | ||
return next().catch(() => { | ||
call.push(4) | ||
}) | ||
}, | ||
function * (next) { | ||
call.push(2) | ||
yield next | ||
call.push(-1) // should not call this | ||
}, | ||
function * (next) { | ||
call.push(3) | ||
yield* next | ||
call.push(-1) // should not call this | ||
}, | ||
(ctx, next) => { | ||
_context = ctx | ||
return Promise.reject(new Error()) | ||
} | ||
) | ||
mw(ctx, function () { | ||
call.push(2) | ||
return Promise.resolve() | ||
}).then(function () { | ||
assert.deepEqual(call, [1, 2, 3]) | ||
done() | ||
}) | ||
return mw(context).then(() => { | ||
assert.equal(context, _context) | ||
assert.deepEqual(call, [1, 2, 3, 4]) | ||
}) | ||
}) | ||
}) | ||
describe('migration snippet', () => { | ||
let app = new Koa() | ||
// snippet | ||
const _use = app.use | ||
app.use = x => _use.call(app, convert(x)) | ||
// end | ||
app.use((ctx, next) => { | ||
ctx.body = [1] | ||
return next().then(() => { | ||
ctx.body.push(9) | ||
}) | ||
}) | ||
app.use(function * (next) { | ||
this.body.push(2) | ||
yield next | ||
this.body.push(8) | ||
}) | ||
app.use(function * (next) { | ||
this.body.push(3) | ||
yield* next | ||
this.body.push(7) | ||
}) | ||
app.use(co.wrap(function * (ctx, next) { | ||
ctx.body.push(4) | ||
yield next() | ||
ctx.body.push(6) | ||
})) | ||
app.use(ctx => { | ||
ctx.body.push(5) | ||
}) | ||
it('should work', done => { | ||
request(app.callback()) | ||
.get('/') | ||
.expect(200, [1, 2, 3, 4, 5, 6, 7, 8, 9]) | ||
.end(done) | ||
}) | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
9291
7
197
0
119
2
4
+ Addedkoa-compose@^3.0.0
+ Addedany-promise@1.3.0(transitive)
+ Addedkoa-compose@3.2.1(transitive)