Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generator support #24

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# editorconfig.org
root = true

[*]
charset = utf-8
indent_size = 2
indent_style = space
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false
17 changes: 17 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use strict';

/** @type {import('eslint').Linter.Config} */
module.exports = {
extends: 'airbnb-base',
parserOptions: {
sourceType: 'script'
},
rules: {
strict: ['error', 'safe'],
'no-underscore-dangle': 'off',
'no-param-reassign': 'off',
'no-unused-vars': ['error', { 'argsIgnorePattern': 'next|res|req|err' }],
'func-names': ['error', 'always', { generators: 'never' }],
'require-yield': 'off'
}
};
22 changes: 0 additions & 22 deletions .eslintrc.json

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ node_modules
.nyc_output/
.tern-port
coverage/
.DS_Store
10 changes: 9 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
language: node_js
node_js:
- "node"
- "8"
- "10"
- "12"
- lts/*
- node

script:
- yarn lint
- yarn test

deploy:
provider: npm
email: [email protected]
Expand Down
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# ExpressJS Async Errors

[![Build Status](https://travis-ci.org/davidbanham/express-async-errors.svg?branch=master)](https://travis-ci.org/davidbanham/express-async-errors)
[![build status](https://badgen.net/travis/davidbanham/express-async-errors/master)](https://travis-ci.com/davidbanham/express-async-errors)
[![install size](https://badgen.net/packagephobia/install/express-async-errors)](https://packagephobia.now.sh/result?p=express-async-errors)
[![npm package version](https://badgen.net/npm/v/express-async-errors)](https://npm.im/express-async-errors)

A dead simple ES6 async/await support hack for [ExpressJS](http://expressjs.com)
A dead simple ES6 generators and async/await support hack for [ExpressJS](http://expressjs.com)

Shamelessly copied from [express-yields](https://github.com/MadRabbit/express-yields)

Expand All @@ -14,7 +16,7 @@ This has been lightly reworked to handle async rather than generators.
npm install express-async-errors --save
```

Then require this script somewhere __before__ you start using it:
Then require this script somewhere **before** you start using it:

Async functions already work fine in Express.

Expand All @@ -28,6 +30,12 @@ app.get('/users', async (req, res) => {
const users = await User.findAll();
res.send(users);
});

// or with generators
app.get('/users', function* (req, res) {
const users = yield User.findAll();
res.send(users);
});
```

This library is about what happens when you hit an error.
Expand Down
48 changes: 28 additions & 20 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,40 @@
'use strict';

const { IncomingMessage, ServerResponse } = require('http');
const co = require('co');
const Layer = require('express/lib/router/layer');
const Router = require('express/lib/router');
const { Router } = require('express');

const last = (arr = []) => arr[arr.length - 1];
const noop = Function.prototype;
// eslint-disable-next-line no-empty-function
const GeneratorFunction = (function* () {}).constructor;

function copyFnProps(oldFn, newFn) {
Object.keys(oldFn).forEach((key) => {
newFn[key] = oldFn[key];
});
return newFn;
const isError = (arg) => arg instanceof Error;
const isGeneratorFunction = (arg) => arg instanceof GeneratorFunction;
const isRequest = (arg) => arg instanceof IncomingMessage;
const isResponse = (arg) => arg instanceof ServerResponse;
const noop = () => {};

function copyProps(source, dest) {
return Object.keys(source).reduce((acc, key) => {
const value = source[key];
return Object.assign(acc, { [key]: value });
}, dest);
}

function wrap(fn) {
const newFn = function newFn(...args) {
if (isGeneratorFunction(fn)) fn = co.wrap(fn);
const ret = fn.apply(this, args);
const next = (args.length === 5 ? args[2] : last(args)) || noop;
if (ret && ret.catch) ret.catch(err => next(err));
const predicates = [isError, isRequest, isResponse];
const next = args.find((arg) => predicates.every((match) => !match(arg))) || noop;
if (ret && ret.catch) ret.catch((err) => next(err));
return ret;
};
Object.defineProperty(newFn, 'length', {
value: fn.length,
writable: false,
});
return copyFnProps(fn, newFn);
}

function patchRouterParam() {
const originalParam = Router.prototype.constructor.param;
Router.prototype.constructor.param = function param(name, fn) {
fn = wrap(fn);
return originalParam.call(this, name, fn);
};
return copyProps(fn, newFn);
}

Object.defineProperty(Layer.prototype, 'handle', {
Expand All @@ -44,4 +48,8 @@ Object.defineProperty(Layer.prototype, 'handle', {
},
});

patchRouterParam();
const originalParam = Router.prototype.constructor.param;
Router.prototype.constructor.param = function param(name, fn) {
fn = wrap(fn);
return originalParam.call(this, name, fn);
};
Loading