Skip to content
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
15 changes: 15 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'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' }]
}
};
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
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# 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)

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 Down
42 changes: 22 additions & 20 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,34 @@
'use strict';

const { IncomingMessage, ServerResponse } = require('http');
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;
const isError = (arg) => arg instanceof Error;
const isRequest = (arg) => arg instanceof IncomingMessage;
const isResponse = (arg) => arg instanceof ServerResponse;
const noop = () => {};

function copyFnProps(oldFn, newFn) {
Object.keys(oldFn).forEach((key) => {
newFn[key] = oldFn[key];
});
return newFn;
function copyProps(source, dest) {
return Object.keys(source).reduce((acc, key) => {
const value = source[key];
return Object.assign(acc, { [key]: value });
}, dest);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you expand on the reason for this refactor?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought reduce serves better purpose conveying message to the reader because source object is reduced (Yeah it is mapped but every mapper is in fact a reducer) to destination one. Plus reduce has return value compared to forEach which I thought is neat and leveraged here.

}

function wrap(fn) {
const newFn = function newFn(...args) {
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 +42,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);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we not change the value of this by removing this section from the wrap closure?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Value of this in this case is determined by Router#param callsite and explicitly forwarded to original implementation using .call binding so it is preserved. Moving it out of a function doesn't change it.

};
Loading