diff --git a/lib/application.js b/lib/application.js index 9caeb0e..c0a3e9a 100644 --- a/lib/application.js +++ b/lib/application.js @@ -5,7 +5,6 @@ * Module dependencies. */ -const isGeneratorFunction = require('is-generator-function'); const debug = require('debug-ms')('koa:application'); const onFinished = require('on-finished'); const response = require('./response'); @@ -18,9 +17,6 @@ const Emitter = require('events'); const util = require('util'); const Stream = require('stream'); const http = require('http'); -const only = require('only'); -const convert = require('koa-convert'); -const deprecate = require('depd')('koa'); /** * Expose `Application` class. @@ -83,11 +79,11 @@ module.exports = class Application extends Emitter { */ toJSON() { - return only(this, [ - 'subdomainOffset', - 'proxy', - 'env' - ]); + return { + subdomainOffset: this.subdomainOffset, + proxy: this.proxy, + env: this.env, + } } /** @@ -113,12 +109,6 @@ module.exports = class Application extends Emitter { use(fn) { if (typeof fn !== 'function') throw new TypeError('middleware must be a function!'); - if (isGeneratorFunction(fn)) { - deprecate('Support for generators will be removed in v3. ' + - 'See the documentation for examples of how to convert old middleware ' + - 'https://github.com/koajs/koa/blob/master/docs/migration.md'); - fn = convert(fn); - } debug('use %s', fn._name || fn.name || '-'); this.middleware.push(fn); return this; diff --git a/lib/context.js b/lib/context.js index 696aa79..85e55dc 100644 --- a/lib/context.js +++ b/lib/context.js @@ -8,7 +8,7 @@ const util = require('util'); const createError = require('http-errors'); const httpAssert = require('http-assert'); -const delegate = require('delegates'); +const delegate = require('./delegates'); const statuses = require('statuses'); /** diff --git a/lib/delegates.js b/lib/delegates.js new file mode 100644 index 0000000..e29760d --- /dev/null +++ b/lib/delegates.js @@ -0,0 +1,157 @@ + +/** + * Expose `Delegator`. + */ + +module.exports = Delegator; + +/** + * Initialize a delegator. + * + * @param {Object} proto + * @param {String} target + * @api public + */ + +function Delegator(proto, target) { + if (!(this instanceof Delegator)) return new Delegator(proto, target); + this.proto = proto; + this.target = target; + this.methods = []; + this.getters = []; + this.setters = []; + this.fluents = []; +} + +/** + * Automatically delegate properties + * from a target prototype + * + * @param {Object} proto + * @param {object} targetProto + * @param {String} targetProp + * @api public + */ + +Delegator.auto = function(proto, targetProto, targetProp){ + var delegator = Delegator(proto, targetProp); + var properties = Object.getOwnPropertyNames(targetProto); + for (var i = 0; i < properties.length; i++) { + var property = properties[i]; + var descriptor = Object.getOwnPropertyDescriptor(targetProto, property); + if (descriptor.get) { + delegator.getter(property); + } + if (descriptor.set) { + delegator.setter(property); + } + if (descriptor.hasOwnProperty('value')) { // could be undefined but writable + var value = descriptor.value; + if (value instanceof Function) { + delegator.method(property); + } else { + delegator.getter(property); + } + if (descriptor.writable) { + delegator.setter(property); + } + } + } +}; + +/** + * Delegate method `name`. + * + * @param {String} name + * @return {Delegator} self + * @api public + */ + +Delegator.prototype.method = function(name){ + var proto = this.proto; + var target = this.target; + this.methods.push(name); + + proto[name] = function(){ + return this[target][name].apply(this[target], arguments); + }; + + return this; +}; + +/** + * Delegator accessor `name`. + * + * @param {String} name + * @return {Delegator} self + * @api public + */ + +Delegator.prototype.access = function(name){ + return this.getter(name).setter(name); +}; + +/** + * Delegator getter `name`. + * + * @param {String} name + * @return {Delegator} self + * @api public + */ + +Delegator.prototype.getter = function(name){ + var proto = this.proto; + var target = this.target; + this.getters.push(name); + + proto.__defineGetter__(name, function(){ + return this[target][name]; + }); + + return this; +}; + +/** + * Delegator setter `name`. + * + * @param {String} name + * @return {Delegator} self + * @api public + */ + +Delegator.prototype.setter = function(name){ + var proto = this.proto; + var target = this.target; + this.setters.push(name); + + proto.__defineSetter__(name, function(val){ + return this[target][name] = val; + }); + + return this; +}; + +/** + * Delegator fluent accessor + * + * @param {String} name + * @return {Delegator} self + * @api public + */ + +Delegator.prototype.fluent = function (name) { + var proto = this.proto; + var target = this.target; + this.fluents.push(name); + + proto[name] = function(val){ + if ('undefined' != typeof val) { + this[target][name] = val; + return this; + } else { + return this[target][name]; + } + }; + + return this; +}; diff --git a/lib/request.js b/lib/request.js index 0b763a9..67a33fa 100644 --- a/lib/request.js +++ b/lib/request.js @@ -12,7 +12,6 @@ const parse = require('parseurl'); const qs = require('querystring'); const typeis = require('type-is'); const fresh = require('fresh'); -const only = require('only'); const util = require('util'); const IP = Symbol('context#ip'); @@ -565,11 +564,11 @@ module.exports = { */ toJSON() { - return only(this, [ - 'method', - 'url', - 'header' - ]); + return { + method: this.method, + url: this.url, + header: this.header, + } } }; diff --git a/lib/response.js b/lib/response.js index 5b2a3c6..d1cee29 100644 --- a/lib/response.js +++ b/lib/response.js @@ -16,7 +16,6 @@ const destroy = require('destroy'); const assert = require('assert'); const extname = require('path').extname; const vary = require('vary'); -const only = require('only'); const util = require('util'); const encodeUrl = require('encodeurl'); @@ -308,6 +307,11 @@ module.exports = { set type(orgType) { let type = orgType + if (!type) { + this.remove('Content-Type'); + return; + } + // If full type is specified, pass it straight on. // Otherwise we do some basic checking for most common // supported mime types. @@ -332,8 +336,10 @@ module.exports = { this.set('Content-Type', 'image/jpeg'); } else if (type.indexOf('gif') >= 0) { this.set('Content-Type', 'image/gif'); - } else if (type.indexOf('text')) { + } else if (type.indexOf('text') >= 0) { this.set('Content-Type', 'text/plain; charset=utf-8'); + } else if (type.indexOf('bin') >= 0) { + this.set('Content-Type', 'application/octet-stream'); } else { this.remove('Content-Type'); } @@ -556,11 +562,11 @@ module.exports = { */ toJSON() { - return only(this, [ - 'status', - 'message', - 'header' - ]); + return { + status: this.status, + message: this.message, + header: this.header, + } }, /** diff --git a/package.json b/package.json index 1912624..741231f 100644 --- a/package.json +++ b/package.json @@ -24,8 +24,6 @@ "dependencies": { "content-disposition": "jharrilim/content-disposition#572383f", "debug-ms": "~4.1.2", - "delegates": "^1.0.0", - "depd": "^1.1.2", "destroy": "^1.0.4", "encodeurl": "^1.0.2", "error-inject": "^1.0.0", @@ -33,12 +31,9 @@ "fresh": "~0.5.2", "http-assert": "^1.3.0", "http-errors": "^1.6.3", - "is-generator-function": "^1.0.7", "koa-compose": "^4.1.0", - "koa-convert": "^1.2.0", "koa-is-json": "^1.0.0", "on-finished": "^2.3.0", - "only": "~0.0.2", "parseurl": "^1.3.2", "statuses": "^1.5.0", "type-is": "^1.6.16", diff --git a/test/application/use.js b/test/application/use.js index 93988fd..d91d988 100644 --- a/test/application/use.js +++ b/test/application/use.js @@ -40,40 +40,6 @@ describe('app.use(fn)', () => { assert.deepEqual(calls, [1, 2, 3, 4, 5, 6]); }); - it('should compose mixed middleware', async() => { - process.once('deprecation', () => {}); // silence deprecation message - const app = new Koa(); - const calls = []; - - app.use((ctx, next) => { - calls.push(1); - return next().then(() => { - calls.push(6); - }); - }); - - app.use(function * (next){ - calls.push(2); - yield next; - calls.push(5); - }); - - app.use((ctx, next) => { - calls.push(3); - return next().then(() => { - calls.push(4); - }); - }); - - const server = app.listen(); - - await request(server) - .get('/') - .expect(404); - - assert.deepEqual(calls, [1, 2, 3, 4, 5, 6]); - }); - // https://github.com/koajs/koa/pull/530#issuecomment-148138051 it('should catch thrown errors in non-async functions', () => { const app = new Koa(); @@ -85,19 +51,6 @@ describe('app.use(fn)', () => { .expect(404); }); - it('should accept both generator and function middleware', () => { - process.once('deprecation', () => {}); // silence deprecation message - const app = new Koa(); - - app.use((ctx, next) => next()); - app.use(function * (next){ this.body = 'generator'; }); - - return request(app.callback()) - .get('/') - .expect(200) - .expect('generator'); - }); - it('should throw error for non function', () => { const app = new Koa(); @@ -105,14 +58,4 @@ describe('app.use(fn)', () => { assert.throws(() => app.use(v), /middleware must be a function!/); }); }); - - it('should output deprecation message for generator functions', done => { - process.once('deprecation', message => { - assert(/Support for generators will be removed/.test(message)); - done(); - }); - - const app = new Koa(); - app.use(function * (){}); - }); });