Comparing version 1.0.0-alpha.17 to 1.0.0-alpha.18
const server = require('../../server'); | ||
const { get, post } = server.router; | ||
server(get('/', ctx => ctx.res.send('Hello 世界'))); | ||
server([ | ||
get('/', ctx => ctx.res.send('Hello 世界')), | ||
get('/page', ctx => ctx.res.send('Hello page')) | ||
]); |
@@ -66,5 +66,9 @@ /* jshint esversion: 6 */ | ||
files: { | ||
'docs/index.html': 'docs/views/index.html.pug', | ||
'docs/about.html': 'docs/views/about.html.pug', | ||
'docs/documentation.html': 'docs/views/documentation.html.pug' | ||
'docs/index.html': 'docs/index.html.pug', | ||
'docs/about/index.html': 'docs/about/index.html.pug', | ||
'docs/documentation/index.html': 'docs/documentation/index.html.pug', | ||
'docs/documentation/server/index.html': 'docs/documentation/server/index.html.pug', | ||
'docs/documentation/middleware/index.html': 'docs/documentation/middleware/index.html.pug', | ||
'docs/documentation/router/index.html': 'docs/documentation/router/index.html.pug', | ||
'docs/documentation/advanced/index.html': 'docs/documentation/advanced/index.html.pug' | ||
} | ||
@@ -71,0 +75,0 @@ } |
{ | ||
"name": "server", | ||
"version": "1.0.0-alpha.17", | ||
"version": "1.0.0-alpha.18", | ||
"description": "A modern and powerful server for Node.js", | ||
@@ -5,0 +5,0 @@ "main": "server.js", |
// Modules - All of the modules that are loaded by default | ||
// For some reason, the tests are in /test/connect.test.js | ||
const modern = require('../../src/modern'); | ||
const renaissance = mod => ctx => { | ||
let res = mod(ctx); | ||
let res = mod(ctx, ctx.options); | ||
return res ? modern(res)(ctx) : Promise.resolve(); | ||
@@ -108,2 +109,6 @@ } | ||
renaissance(ctx => { | ||
if (!ctx.options.middle) return; | ||
}) | ||
// TODO: connectTimeout: require('connect-timeout'), | ||
@@ -110,0 +115,0 @@ // TODO: vhost: require('vhost'), |
@@ -1,4 +0,4 @@ | ||
# Server | ||
# **Server** for Node.js | ||
**Simple and powerful server** for Node.js: | ||
Simple and powerful server that just works so **you can focus on your awesome project**: | ||
@@ -26,3 +26,3 @@ ```js | ||
After getting Node ready and `npm init`, run this in your project folder to **install the server**: | ||
After getting Node.js ready and `npm init`, run this in your project folder to **install the server**: | ||
@@ -37,4 +37,4 @@ ```bash | ||
// Include the server in your file | ||
let server = require('server'); | ||
let { get, post } = server.router; | ||
const server = require('server'); | ||
const { get, post } = server.router; | ||
@@ -79,12 +79,8 @@ // Initialize the server on port 3000 | ||
I love using my work and I'm available for contractor work. Freelancing helps maintain `server` and [my other open source projects](https://github.com/franciscop/) up to date! Hire me to do: | ||
## Hire me | ||
I love using my work in real life and I'm available for contractor work. My freelancing helps keep `server` and [my other open source projects](https://github.com/franciscop/) up to date! Hire me to do: | ||
- Front-end: [Picnic CSS](http://picnicss.com/) ♦ [Paperdocs](http://francisco.io/paperdocs) ♦ [Angular Attack](http://angularattack.com/) ♦ [Ruby Rampage](https://www.rubyrampage.com/) ♦ [Server JS website](https://serverjs.io/) | ||
- Full-stack: [Makers UPV](https://makersupv.com/) ♦ [Learning vocabulary](http://anchor.science/) | ||
- Back-end: [Server JS (the library)](http://serverjs.io/) ♦ [Drive DB](https://github.com/franciscop/drive-db) ♦ [Express Data Parser](https://github.com/franciscop/express-data-parser) | ||
- Back-end: [Server JS (the library)](http://serverjs.io/) ♦ [Drive DB](https://github.com/franciscop/drive-db) ♦ [Express Data Parser](https://github.com/franciscop/express-data-parser) | ||
Find my email [in my website](http://francisco.io/). | ||
You can also sponsor the project and your logo will be shown here with ∞ ♥. Open an issue to have an open conversation or contact me directly (email [in my website](http://francisco.io/)). |
@@ -14,2 +14,3 @@ // server for Node.js (https://serverjs.io/) | ||
const modern = require('./src/modern'); | ||
const error = require('./src/error'); | ||
const plugins = [ | ||
@@ -24,7 +25,15 @@ require('./plugins/middle') | ||
const opts = middle[0] instanceof Function ? {} : middle.shift(); | ||
// First parameter can be: | ||
// - Number (opts) | ||
// - Object (opts) => cannot be ID'd | ||
// - Boolean (middle) | ||
// - Function (middle) | ||
// - Array (middle) | ||
const opts = (typeof middle[0] === 'boolean' || | ||
middle[0] instanceof Function || | ||
middle[0] instanceof Array | ||
) ? {} : middle.shift(); | ||
this.express = express; | ||
this.app = this.express(); | ||
this.modern = modern; | ||
@@ -34,2 +43,5 @@ // Set the options for the context of Server.js | ||
this.modern = modern; | ||
this.error = error(this.options.errors); | ||
// Create the initial context | ||
@@ -36,0 +48,0 @@ const context = (req, res) => Object.assign({}, this, { req: req, res: res }); |
@@ -1,2 +0,2 @@ | ||
const errors = require('human-error'); | ||
const errors = require('human-error')({}); | ||
@@ -3,0 +3,0 @@ errors.NotSoSecret = () => ` |
@@ -6,6 +6,12 @@ const load = require('loadware'); | ||
const handler = err => { | ||
ctx.error = err; | ||
if (next.error && next instanceof Function) next.error(ctx); | ||
}; | ||
// Make sure that we pass the original context to the next promise | ||
return prev.then(next).then(fake => ctx); | ||
// Catched errors should not be passed to the next thing | ||
return prev.catch(handler).then(fake => ctx).then(next).then(fake => ctx); | ||
// Get it started with the right context | ||
}, Promise.resolve(ctx)); |
@@ -5,16 +5,18 @@ const join = require('../join'); | ||
// Generic request handler | ||
const generic = (path, method, ...promises) => ctx => { | ||
// TODO: optimize? by extracting params(path) outside | ||
const generic = (method, ...middle) => ctx => { | ||
// A route should be solved only once | ||
if (ctx.req.solved) return; | ||
// Only for the correct methods | ||
if (method !== ctx.req.method && method !== 'ALL') return; | ||
if (method !== ctx.req.method) return; | ||
// Only do this if the correct path | ||
const path = typeof middle[0] === 'string' ? middle.shift() : '*'; | ||
ctx.req.params = params(path)(ctx.req.url); | ||
if (!ctx.req.params) return; | ||
// It can/should be solved only once | ||
if (ctx.req.solved) return; | ||
// Perform this promise chain | ||
return join(promises)(ctx).then(ctx => { | ||
return join(middle)(ctx).then(ctx => { | ||
ctx.req.solved = true; | ||
@@ -26,6 +28,21 @@ return ctx; | ||
// Create a middleware that splits paths | ||
exports.all = (path, ...middle) => generic(path, 'ALL', ...middle); | ||
exports.get = (path, ...middle) => generic(path, 'GET', ...middle); | ||
exports.post = (path, ...middle) => generic(path, 'POST', ...middle); | ||
exports.put = (path, ...middle) => generic(path, 'PUT', ...middle); | ||
exports.del = (path, ...middle) => generic(path, 'DELETE', ...middle); | ||
exports.all = (...middle) => generic( 'ALL', ...middle); | ||
exports.get = (...middle) => generic( 'GET', ...middle); | ||
exports.post = (...middle) => generic( 'POST', ...middle); | ||
exports.put = (...middle) => generic( 'PUT', ...middle); | ||
exports.del = (...middle) => generic('DELETE', ...middle); | ||
exports.error = (...middle) => { | ||
let path = typeof middle[0] === 'string' ? middle.shift() : false; | ||
let parser = params(path); | ||
let generic = () => {}; | ||
generic.error = ctx => { | ||
// All of them if there's no path | ||
if (!path) return join(middle)(ctx); | ||
const frag = ctx.error.path ? ctx.error.path.slice(0, path.length) : ''; | ||
if (frag === path) return join(middle)(ctx); | ||
throw ctx.error; | ||
} | ||
return generic; | ||
} |
const extend = require('extend'); | ||
const loadware = require('loadware'); | ||
const join = require('../join'); | ||
const { get } = require('./index'); | ||
const { get, error } = require('./index'); | ||
const { handler, getter } = require('../../tests/helpers'); | ||
const createCtx = (opts = {}) => extend({ | ||
@@ -57,1 +59,63 @@ req: { url: '/', method: 'GET' }, | ||
}); | ||
describe('Error routes', () => { | ||
it('can catch errors', () => { | ||
const generate = ctx => { throw new Error('Should be caught'); }; | ||
const handle = error(ctx => ctx.res.send('Error 世界')); | ||
return getter([generate, handle]).then(res => { | ||
expect(res.body).toBe('Error 世界'); | ||
}); | ||
}); | ||
it('can catch errors with full path', () => { | ||
const generate = ctx => ctx.error('test:a'); | ||
const handle = error('test:a', ctx => { | ||
expect(ctx.error).toBeInstanceOf(Error); | ||
expect(ctx.error.message).toBe('test:a'); | ||
ctx.res.send('Error 世界'); | ||
}); | ||
return getter([generate, handle]).then(res => { | ||
expect(res.body).toBe('Error 世界'); | ||
}); | ||
}); | ||
it('can catch errors with partial path', () => { | ||
const generate = ctx => ctx.error('test:b'); | ||
const handle = error('test', ctx => { | ||
expect(ctx.error).toBeInstanceOf(Error); | ||
expect(ctx.error.message).toBe('test:b'); | ||
ctx.res.send('Error 世界'); | ||
}); | ||
return getter([generate, handle]).then(res => { | ||
expect(res.body).toBe('Error 世界'); | ||
}); | ||
}); | ||
const errors = { | ||
'test:pre:1': new Error('Hi there 1'), | ||
'test:pre:a': new Error('Hi there a'), | ||
'test:pre:b': new Error('Hi there b'), | ||
}; | ||
it('can generate errors', () => { | ||
const generate = ctx => ctx.error('test:pre:1'); | ||
const handle = error('test', ctx => { | ||
expect(ctx.error).toBeInstanceOf(Error); | ||
expect(ctx.error.message).toBe('Hi there 1'); | ||
ctx.res.send(); | ||
}); | ||
return getter([generate, handle], {}, { errors }); | ||
}); | ||
it('can generate errors', () => { | ||
const generate = ctx => ctx.error('generic error'); | ||
const handle = error('generic error', ctx => { | ||
expect(ctx.error).toBeInstanceOf(Error); | ||
expect(ctx.error.message).toBe('generic error'); | ||
ctx.res.send(); | ||
}); | ||
return getter([generate, handle], {}, { errors }); | ||
}); | ||
}); |
@@ -8,4 +8,16 @@ let request = require('request'); | ||
const content = type => ctx => { | ||
expect(ctx.req.headers['content-type']).toBe(type); | ||
} | ||
describe('Default modules', () => { | ||
it('can cancel all bodyparser', () => { | ||
let middle = ctx => { | ||
expect(ctx.req.body).toBe(undefined); | ||
ctx.res.send(); | ||
}; | ||
return poster(middle, data, { middle: false }); | ||
}); | ||
it('bodyParser', () => { | ||
@@ -20,2 +32,11 @@ let middle = ctx => { | ||
it('bodyParser can be cancelled', () => { | ||
let middle = ctx => { | ||
expect(ctx.req.body).toEqual({}); | ||
expect(ctx.req.headers['content-type']).toBe('application/x-www-form-urlencoded'); | ||
ctx.res.send(); | ||
}; | ||
return poster(middle, data, { middle: { bodyParser: false } }); | ||
}); | ||
it('jsonParser', done => { | ||
@@ -22,0 +43,0 @@ let middle = ctx => { |
@@ -45,8 +45,8 @@ let request = require('request'); | ||
exports.getter = (middle, data = {}) => exports.handler(get('/', middle), { | ||
exports.getter = (middle, data = {}, opts) => exports.handler(get('/', middle), { | ||
form: data | ||
}); | ||
}, opts); | ||
exports.poster = (middle, data = {}) => exports.handler(post('/', middle), { | ||
exports.poster = (middle, data = {}, opts) => exports.handler(post('/', middle), { | ||
form: data, method: 'POST' | ||
}); | ||
}, opts); |
@@ -1,7 +0,19 @@ | ||
let server = require('server'); | ||
let request = require('request'); | ||
let { get } = server.router; | ||
let { handler, getter } = require('./helpers'); | ||
const server = require('server'); | ||
const req = require('request-promise-native'); | ||
const request = opts => { | ||
opts = typeof opts === 'string' ? { uri: opts } : opts; | ||
return req(Object.assign({}, opts, { resolveWithFullResponse: true })); | ||
} | ||
const { get, error } = server.router; | ||
const { handler, getter } = require('./helpers'); | ||
const hello = ctx => ctx.res.send('Hello 世界'); | ||
const randPort = ctx => ctx.options.port = 2000 + parseInt(Math.random() * 10000); | ||
const wait = time => new Promise((resolve, reject) => setTimeout(resolve, time)); | ||
// Make a request to the right port, get the response and close the connection | ||
const autorequest = ctx => request(`http://localhost:${ctx.options.port}/`) | ||
.then(res => { ctx.close(); return res; }); | ||
describe('Middleware', () => { | ||
@@ -15,2 +27,25 @@ it('loads as a function', done => { | ||
it('loads as an array', done => { | ||
getter([ctx => ctx.res.send('Hello 世界')]).then(res => { | ||
expect(res.body).toBe('Hello 世界'); | ||
done(); | ||
}); | ||
}); | ||
// NOTE: port has to be changed for parallel tests | ||
it('loads as an function in the first parameter', () => { | ||
return server(hello).then(autorequest).then(res => { | ||
expect(res.body).toBe('Hello 世界'); | ||
}); | ||
}); | ||
it('loads as an array in the first parameter', () => { | ||
// After others have finished | ||
return wait(1000).then(() => { | ||
server([hello]).then(autorequest).then(res => { | ||
expect(res.body).toBe('Hello 世界'); | ||
}); | ||
}); | ||
}); | ||
it('has a valid context', () => { | ||
@@ -17,0 +52,0 @@ return getter(ctx => { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
91
1573
1
879133
84