Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
acebd1e5c0 | ||
|
d678d066c3 | ||
|
2245de31d7 | ||
|
065b500561 | ||
|
75b130ef91 | ||
|
72598f09e1 | ||
|
d7cfd6d9f3 | ||
|
21f5dea449 | ||
|
a1e56dc6c3 | ||
|
34b7580d18 | ||
|
4ab3fa2626 | ||
|
5b45250bf5 | ||
|
787a22ed44 | ||
|
79062fe337 | ||
|
f90743d4cf |
3
.babelrc
3
.babelrc
@ -1,4 +1,3 @@
|
|||||||
{
|
{
|
||||||
"presets": ["es2015"],
|
"presets": ["es2015"]
|
||||||
"plugins": ["add-module-exports"]
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
index.js
|
|
||||||
frontexpress.js
|
|
||||||
frontexpress.min.js
|
|
||||||
frontexpress.min.js.map
|
|
||||||
gzipsize.js
|
|
||||||
test
|
|
||||||
coverage
|
|
298
README.md
298
README.md
@ -1,38 +1,16 @@
|
|||||||

|

|
||||||
|
|
||||||
Frontexpress manages routes in browser like [ExpressJS](http://expressjs.com/) does on Node.
|
A simple vanilla JavaScript router a la [ExpressJS](http://expressjs.com/).
|
||||||
|
|
||||||
Same language same API on all the stack.
|
Code the front-end like the back-end.
|
||||||
|
|
||||||
|
[frontexpress demo](https://github.com/camelaissani/frontexpress-demo)
|
||||||
|
|
||||||
[](https://travis-ci.org/camelaissani/frontexpress)
|
[](https://travis-ci.org/camelaissani/frontexpress)
|
||||||
[](https://codeclimate.com/github/camelaissani/frontexpress)
|
[](https://codeclimate.com/github/camelaissani/frontexpress)
|
||||||
[](https://coveralls.io/github/camelaissani/frontexpress?branch=master)
|
[](https://coveralls.io/github/camelaissani/frontexpress?branch=master)
|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
Code the front-end logic with the same style than on the back-end with express
|
|
||||||
|
|
||||||
```js
|
|
||||||
import frontexpress from 'frontexpress';
|
|
||||||
|
|
||||||
// Front-end application
|
|
||||||
const app = frontexpress();
|
|
||||||
|
|
||||||
// front-end logic on navigation path "/page1"
|
|
||||||
app.get('/page1', (req, res) => {
|
|
||||||
document.querySelector('.content').innerHTML = `<h1>Page 1 content</h1>`;
|
|
||||||
});
|
|
||||||
|
|
||||||
// front-end logic on navigation path "/page2"
|
|
||||||
app.get('/page2', (req, res) => {
|
|
||||||
document.querySelector('.content').innerHTML = `<h1>Page 2 content</h1>`;
|
|
||||||
});
|
|
||||||
|
|
||||||
// start front-end application
|
|
||||||
app.listen(() => {
|
|
||||||
// on DOM ready
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@ -50,45 +28,33 @@ $ bower install frontexpress
|
|||||||
|
|
||||||
### From CDN
|
### From CDN
|
||||||
|
|
||||||
On [jsDelivr](http://www.jsdelivr.com/?query=frontexpress)
|
On [jsDelivr](https://cdn.jsdelivr.net/npm/frontexpress@1.2.0/frontexpress.min.js)
|
||||||
|
|
||||||
## Quick Start
|
## Usage
|
||||||
|
|
||||||
The quickest way to get started with frontexpress is to clone the [frontexpress-demo](https://github.com/camelaissani/frontexpress-demo) repository.
|
```js
|
||||||
|
import frontexpress from 'frontexpress';
|
||||||
|
|
||||||
## Tests
|
// Front-end application
|
||||||
|
const app = frontexpress();
|
||||||
|
|
||||||
Clone the git repository:
|
// front-end logic on navigation path "/page1"
|
||||||
|
app.get('/page1', (req, res) => {
|
||||||
|
document.querySelector('.content').innerHTML = res.responseText;
|
||||||
|
});
|
||||||
|
|
||||||
```bash
|
// front-end logic on navigation path "/page2"
|
||||||
$ git clone git@github.com:camelaissani/frontexpress.git
|
app.get('/page2', (req, res) => {
|
||||||
$ cd frontexpress
|
document.querySelector('.content').innerHTML = res.responseText;
|
||||||
|
});
|
||||||
|
|
||||||
|
// start front-end application
|
||||||
|
app.listen();
|
||||||
```
|
```
|
||||||
|
|
||||||
Install the dependencies and run the test suite:
|
### Routes
|
||||||
|
|
||||||
```bash
|
Listen GET requests on path /hello:
|
||||||
$ npm install
|
|
||||||
$ npm test
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Navigation path and frontexpress routing
|
|
||||||
|
|
||||||
### Disclaimer
|
|
||||||
|
|
||||||
>
|
|
||||||
> In this first version of frontexpress, the API is not completely the mirror of the expressjs one.
|
|
||||||
>
|
|
||||||
> There are some missing methods. Currently, the use, get, post... methods having a middleware array as parameter are not available.
|
|
||||||
> The string pattern to define route paths is not yet implemented.
|
|
||||||
>
|
|
||||||
> Obviously, the objective is to have the same API as expressjs when the methods make sense browser side.
|
|
||||||
>
|
|
||||||
|
|
||||||
### Basic routing
|
|
||||||
|
|
||||||
Listen navigation (GET request) on path /hello:
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
app.get('/hello', (req, res) => {
|
app.get('/hello', (req, res) => {
|
||||||
@ -96,7 +62,7 @@ app.get('/hello', (req, res) => {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
Listen a POST request on path /item:
|
Listen POST requests on path /item:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
app.post('/item', (req, res) => {
|
app.post('/item', (req, res) => {
|
||||||
@ -104,9 +70,7 @@ app.post('/item', (req, res) => {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Routing based on RegExp
|
Listen GET requests on path starting with /api/:
|
||||||
|
|
||||||
Listen navigation on paths which start with /api/:
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
app.get(/^api\//, (req, res) => {
|
app.get(/^api\//, (req, res) => {
|
||||||
@ -114,6 +78,68 @@ app.get(/^api\//, (req, res) => {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Get parameters from path
|
||||||
|
|
||||||
|
```js
|
||||||
|
app.get('/product/:id', (req, res) => {
|
||||||
|
// if we have /product/42 then
|
||||||
|
// req.params.id = 42
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
app.get('/user/:firstname?/:lastname', (req, res) => {
|
||||||
|
// if we have /user/camel/aissani then
|
||||||
|
// req.params.firstname = 'camel'
|
||||||
|
// req.params.lastname = 'aissani'
|
||||||
|
|
||||||
|
// if we have /user/aissani then
|
||||||
|
// req.params.firstname = undefined
|
||||||
|
// req.params.lastname = 'aissani'
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
app.get('/user/:id', (req, res) => {
|
||||||
|
// if we have /user/1,2,3 then
|
||||||
|
// req.params.id = [1,2,3]
|
||||||
|
});
|
||||||
|
```
|
||||||
|
You can have the full capabilities of Express-style path with this plugin [frontexpress-path-to-regexp](https://github.com/camelaissani/frontexpress-path-to-regexp)
|
||||||
|
|
||||||
|
### Middleware object
|
||||||
|
|
||||||
|
The middleware object gives access to more hooks
|
||||||
|
|
||||||
|
```js
|
||||||
|
class MyMiddleware = new Middleware {
|
||||||
|
entered(req) {
|
||||||
|
// before request sent
|
||||||
|
}
|
||||||
|
|
||||||
|
updated(req, res) {
|
||||||
|
// after request sent
|
||||||
|
// res has the request response
|
||||||
|
window.alert('Hello World');
|
||||||
|
}
|
||||||
|
|
||||||
|
exited(req) {
|
||||||
|
// before a new request sent
|
||||||
|
}
|
||||||
|
|
||||||
|
failed(req, res) {
|
||||||
|
// on request failed
|
||||||
|
}
|
||||||
|
|
||||||
|
next() {
|
||||||
|
// for chaining
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
app.get('/hello', new MyMiddleware());
|
||||||
|
```
|
||||||
|
|
||||||
### Chain handlers
|
### Chain handlers
|
||||||
|
|
||||||
You can provide multiple handlers functions on a navigation path. Invoking ```next()``` function allows to chain the handlers.
|
You can provide multiple handlers functions on a navigation path. Invoking ```next()``` function allows to chain the handlers.
|
||||||
@ -138,7 +164,7 @@ h2!
|
|||||||
|
|
||||||
h3 is ignored because ```next()``` function was not invoked.
|
h3 is ignored because ```next()``` function was not invoked.
|
||||||
|
|
||||||
### app.route()
|
#### app.route()
|
||||||
|
|
||||||
You can create chainable route handlers for a route path by using ```app.route()```.
|
You can create chainable route handlers for a route path by using ```app.route()```.
|
||||||
|
|
||||||
@ -149,7 +175,7 @@ app.route('/book')
|
|||||||
.put((req, res) => { console.log('Update the book') });
|
.put((req, res) => { console.log('Update the book') });
|
||||||
```
|
```
|
||||||
|
|
||||||
### frontexpress.Router
|
#### frontexpress.Router
|
||||||
|
|
||||||
Use the ```frontexpress.Router``` class to create modular, mountable route handlers.
|
Use the ```frontexpress.Router``` class to create modular, mountable route handlers.
|
||||||
|
|
||||||
@ -187,121 +213,77 @@ import birds from './birds';
|
|||||||
app.use('/birds', birds);
|
app.use('/birds', birds);
|
||||||
```
|
```
|
||||||
|
|
||||||
## API
|
## Plugins
|
||||||
|
|
||||||
| | Method | Short description |
|
### Extend frontexpress via plugins:
|
||||||
| :------------- | :--------------| :----------------- |
|
|
||||||
|Frontexpress |||
|
|
||||||
||[frontexpress()](https://github.com/camelaissani/frontexpress/blob/master/docs/frontexpress.md#frontexpress-1)|Creates an instance of application|
|
|
||||||
||[frontexpress.Router()](https://github.com/camelaissani/frontexpress/blob/master/docs/frontexpress.md#frontexpressrouter)|Creates a Router object|
|
|
||||||
||[frontexpress.Middleware](https://github.com/camelaissani/frontexpress/blob/master/docs/frontexpress.md#frontexpressmiddleware)|Returns the Middleware class |
|
|
||||||
||||
|
|
||||||
|Application |||
|
|
||||||
||[set(setting, value)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationsetsetting-val)|Assigns a setting|
|
|
||||||
||[listen(callback)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationlistencallback)|Starts the application|
|
|
||||||
||[route(uri)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationrouteuri)|Gets a Router initialized with a root path|
|
|
||||||
||[use(uri, middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationuseuri-middleware)|Sets a middleware|
|
|
||||||
||||
|
|
||||||
||[get(uri, middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationgeturi-middleware-applicationposturi-middleware)|Applies a middleware on given path for a GET request|
|
|
||||||
||[post(uri, middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationgeturi-middleware-applicationposturi-middleware)|Applies a middleware on given path for a POST request|
|
|
||||||
||[put(uri, middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationgeturi-middleware-applicationposturi-middleware)|Applies a middleware on given path for a PUT request|
|
|
||||||
||[delete(uri, middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationgeturi-middleware-applicationposturi-middleware)|Applies a middleware on given path for a DELETE request|
|
|
||||||
||||
|
|
||||||
||[httpGet(request, success, failure)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationhttpgetrequest-success-failure-applicationhttppostrequest-success-failure)|Invokes a GET ajax request|
|
|
||||||
||[httpPost(request, success, failure)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationhttpgetrequest-success-failure-applicationhttppostrequest-success-failure)|Invokes a POST ajax request|
|
|
||||||
||[httpPut(request, success, failure)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationhttpgetrequest-success-failure-applicationhttppostrequest-success-failure)|Invokes a PUT ajax request|
|
|
||||||
||[httpDelete(request, success, failure)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationhttpgetrequest-success-failure-applicationhttppostrequest-success-failure)|Invokes a DELETE ajax request|
|
|
||||||
||||
|
|
||||||
|Router |||
|
|
||||||
||[use(middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/router.md#routerusemiddleware)|Sets a middleware|
|
|
||||||
||[all(middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/router.md#routerallmiddleware)|Sets a middleware on all HTTP method requests|
|
|
||||||
||||
|
|
||||||
||[get(uri, middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/router.md#routergeturi-middleware-routerposturi-middleware)|Applies a middleware on given path for a GET request|
|
|
||||||
||[post(uri, middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/router.md#routergeturi-middleware-routerposturi-middleware)|Applies a middleware on given path for a POST request|
|
|
||||||
||[put(uri, middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/router.md#routergeturi-middleware-routerposturi-middleware)|Applies a middleware on given path for a PUT request|
|
|
||||||
||[delete(uri, middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/router.md#routergeturi-middleware-routerposturi-middleware)|Applies a middleware on given path for a DELETE request|
|
|
||||||
||||
|
|
||||||
|Middleware |||
|
|
||||||
||[entered(request)](https://github.com/camelaissani/frontexpress/blob/master/docs/middleware.md#middlewareenteredrequest)|Invoked by the app before an ajax request is sent|
|
|
||||||
||[exited(request)](https://github.com/camelaissani/frontexpress/blob/master/docs/middleware.md#middlewareexitedrequest)|Invoked by the app before a new ajax request is sent|
|
|
||||||
||[updated(request, response)](https://github.com/camelaissani/frontexpress/blob/master/docs/middleware.md#middlewareupdatedrequest-response)|Invoked by the app after an ajax request has responded|
|
|
||||||
||[failed(request, response)](https://github.com/camelaissani/frontexpress/blob/master/docs/middleware.md#middlewarefailedrequest-response)|Invoked by the app after an ajax request has failed|
|
|
||||||
||[next()](https://github.com/camelaissani/frontexpress/blob/master/docs/middleware.md#middlewarenext)|Allows to break the middleware chain execution|
|
|
||||||
|
|
||||||
|
- [frontexpress-path-to-regexp](https://github.com/camelaissani/frontexpress-path-to-regexp): Add the ability to support Express-style path string such as /user/:name, /user*...
|
||||||
|
|
||||||
### middleware function
|
Others are coming
|
||||||
|
|
||||||
After registering a middleware function, the application invokes it with these parameters:
|
### Write your own plugin
|
||||||
|
|
||||||
|
It consists to simply create an object with two properties:
|
||||||
|
- **name**: the name of your plugin
|
||||||
|
- **plugin**: the function containing the implementation
|
||||||
|
|
||||||
|
Let's assume that we have implemented this plugin in the `frontexpress-my-plugin.js` file as below:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
(request, response, next) => {
|
export default {
|
||||||
next();
|
name: 'My plugin',
|
||||||
|
plugin(app) {
|
||||||
|
// the plugin implementation goes here
|
||||||
|
|
||||||
|
// Some ideas
|
||||||
|
// you can get settings
|
||||||
|
// const transformer = app.get('http GET transformer');
|
||||||
|
//
|
||||||
|
// you can set settings
|
||||||
|
// app.set('http requester', {
|
||||||
|
// fetch() {
|
||||||
|
// ...
|
||||||
|
// }});
|
||||||
|
//
|
||||||
|
// you can complete routes
|
||||||
|
// app.get(...)
|
||||||
}
|
}
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
**request**: `Object`, the ajax request information sent by the app
|
To use it:
|
||||||
|
|
||||||
**response**: `Object`, the response of request
|
|
||||||
|
|
||||||
**next**: `Function`, the `next()` function to call to not break the middleware execution chain
|
|
||||||
|
|
||||||
|
|
||||||
### request object
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
{
|
import frontexpress from 'frontexpress';
|
||||||
method,
|
import myPlugin from 'frontexpress-my-plugin';
|
||||||
uri,
|
|
||||||
headers,
|
// Front-end application
|
||||||
data,
|
const app = frontexpress();
|
||||||
history: {
|
|
||||||
state,
|
// tell to frontexpress to use your plugin
|
||||||
title,
|
app.use(myPlugin);
|
||||||
uri
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**method**: `String`, HTTP methods 'GET', 'POST'...
|
## More
|
||||||
|
|
||||||
**uri**: `String`, path
|
[API](https://github.com/camelaissani/frontexpress/blob/master/docs/api.md)
|
||||||
|
|
||||||
**headers**: `Object`, custom HTTP headers
|
## Tests
|
||||||
|
|
||||||
**data**: `Object`, data attached to the request
|
Clone the git repository:
|
||||||
|
|
||||||
**history**: `Object`, object with properties state, title and uri
|
```bash
|
||||||
|
$ git clone git@github.com:camelaissani/frontexpress.git
|
||||||
**If the history object is set, it will activate the browser history management.** See [browser pushState() method](https://developer.mozilla.org/en-US/docs/Web/API/History_API#The_pushState()_method) for more information about state, title, and uri (url).
|
$ cd frontexpress
|
||||||
|
|
||||||
> uri and history.uri can be different.
|
|
||||||
|
|
||||||
|
|
||||||
### response object
|
|
||||||
|
|
||||||
```js
|
|
||||||
{
|
|
||||||
status,
|
|
||||||
statusText,
|
|
||||||
responseText,
|
|
||||||
errorThrown,
|
|
||||||
errors
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**status**: `Number`, HTTP status 200, 404, 401, 500...
|
Install the dependencies and run the test suite:
|
||||||
|
|
||||||
**statusText**: `String`
|
|
||||||
|
|
||||||
**responseText**: `String` response content
|
|
||||||
|
|
||||||
**errorThrown**: `Object` exception thrown (if request fails)
|
|
||||||
|
|
||||||
**errors**: `String` error description (if request fails)
|
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ npm install
|
||||||
|
$ npm test
|
||||||
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
[MIT](LICENSE)
|
[MIT](LICENSE)
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
"ignore": [
|
"ignore": [
|
||||||
"**/.*",
|
"**/.*",
|
||||||
"index.js",
|
"index.js",
|
||||||
|
"gzipsize.js",
|
||||||
"rollup.config.dev.js",
|
"rollup.config.dev.js",
|
||||||
"rollup.config.prod.js",
|
"rollup.config.prod.js",
|
||||||
"node_modules",
|
"node_modules",
|
||||||
|
109
docs/api.md
Normal file
109
docs/api.md
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
# API
|
||||||
|
|
||||||
|
| | Method | Short description |
|
||||||
|
| :------------- | :--------------| :----------------- |
|
||||||
|
|Frontexpress |||
|
||||||
|
||[frontexpress()](https://github.com/camelaissani/frontexpress/blob/master/docs/frontexpress.md#frontexpress-1)|Creates an instance of application|
|
||||||
|
||[frontexpress.Router()](https://github.com/camelaissani/frontexpress/blob/master/docs/frontexpress.md#frontexpressrouter)|Creates a Router object|
|
||||||
|
||[frontexpress.Middleware](https://github.com/camelaissani/frontexpress/blob/master/docs/frontexpress.md#frontexpressmiddleware)|Returns the Middleware class |
|
||||||
|
||||
|
||||||
|
|Application |||
|
||||||
|
||[set(setting, value)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationsetsetting-val)|Assigns a setting|
|
||||||
|
||[listen(callback)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationlistencallback)|Starts the application|
|
||||||
|
||[route(uri)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationrouteuri)|Gets a Router initialized with a root path|
|
||||||
|
||[use(uri, middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationuseuri-middleware)|Sets a middleware|
|
||||||
|
||||
|
||||||
|
||[get(uri, middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationgeturi-middleware-applicationposturi-middleware)|Applies a middleware on given path for a GET request|
|
||||||
|
||[post(uri, middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationgeturi-middleware-applicationposturi-middleware)|Applies a middleware on given path for a POST request|
|
||||||
|
||[put(uri, middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationgeturi-middleware-applicationposturi-middleware)|Applies a middleware on given path for a PUT request|
|
||||||
|
||[delete(uri, middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationgeturi-middleware-applicationposturi-middleware)|Applies a middleware on given path for a DELETE request|
|
||||||
|
||||
|
||||||
|
||[httpGet(request, success, failure)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationhttpgetrequest-success-failure-applicationhttppostrequest-success-failure)|Invokes a GET ajax request|
|
||||||
|
||[httpPost(request, success, failure)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationhttpgetrequest-success-failure-applicationhttppostrequest-success-failure)|Invokes a POST ajax request|
|
||||||
|
||[httpPut(request, success, failure)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationhttpgetrequest-success-failure-applicationhttppostrequest-success-failure)|Invokes a PUT ajax request|
|
||||||
|
||[httpDelete(request, success, failure)](https://github.com/camelaissani/frontexpress/blob/master/docs/application.md#applicationhttpgetrequest-success-failure-applicationhttppostrequest-success-failure)|Invokes a DELETE ajax request|
|
||||||
|
||||
|
||||||
|
|Router |||
|
||||||
|
||[use(middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/router.md#routerusemiddleware)|Sets a middleware|
|
||||||
|
||[all(middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/router.md#routerallmiddleware)|Sets a middleware on all HTTP method requests|
|
||||||
|
||||
|
||||||
|
||[get(uri, middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/router.md#routergeturi-middleware-routerposturi-middleware)|Applies a middleware on given path for a GET request|
|
||||||
|
||[post(uri, middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/router.md#routergeturi-middleware-routerposturi-middleware)|Applies a middleware on given path for a POST request|
|
||||||
|
||[put(uri, middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/router.md#routergeturi-middleware-routerposturi-middleware)|Applies a middleware on given path for a PUT request|
|
||||||
|
||[delete(uri, middleware)](https://github.com/camelaissani/frontexpress/blob/master/docs/router.md#routergeturi-middleware-routerposturi-middleware)|Applies a middleware on given path for a DELETE request|
|
||||||
|
||||
|
||||||
|
|Middleware |||
|
||||||
|
||[entered(request)](https://github.com/camelaissani/frontexpress/blob/master/docs/middleware.md#middlewareenteredrequest)|Invoked by the app before an ajax request is sent|
|
||||||
|
||[exited(request)](https://github.com/camelaissani/frontexpress/blob/master/docs/middleware.md#middlewareexitedrequest)|Invoked by the app before a new ajax request is sent|
|
||||||
|
||[updated(request, response)](https://github.com/camelaissani/frontexpress/blob/master/docs/middleware.md#middlewareupdatedrequest-response)|Invoked by the app after an ajax request has responded|
|
||||||
|
||[failed(request, response)](https://github.com/camelaissani/frontexpress/blob/master/docs/middleware.md#middlewarefailedrequest-response)|Invoked by the app after an ajax request has failed|
|
||||||
|
||[next()](https://github.com/camelaissani/frontexpress/blob/master/docs/middleware.md#middlewarenext)|Allows to break the middleware chain execution|
|
||||||
|
|
||||||
|
# middleware function
|
||||||
|
|
||||||
|
After registering a middleware function, the application invokes it with these parameters:
|
||||||
|
|
||||||
|
```js
|
||||||
|
(request, response, next) => {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**request**: `Object`, the ajax request information sent by the app
|
||||||
|
|
||||||
|
**response**: `Object`, the response of request
|
||||||
|
|
||||||
|
**next**: `Function`, the `next()` function to call to not break the middleware execution chain
|
||||||
|
|
||||||
|
# request object
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
method,
|
||||||
|
uri,
|
||||||
|
headers,
|
||||||
|
data,
|
||||||
|
history: {
|
||||||
|
state,
|
||||||
|
title,
|
||||||
|
uri
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**method**: `String`, HTTP methods 'GET', 'POST'...
|
||||||
|
|
||||||
|
**uri**: `String`, path
|
||||||
|
|
||||||
|
**headers**: `Object`, custom HTTP headers
|
||||||
|
|
||||||
|
**data**: `Object`, data attached to the request
|
||||||
|
|
||||||
|
**history**: `Object`, object with properties state, title and uri
|
||||||
|
|
||||||
|
>**If the history object is set, it will activate the browser history management.** See [browser pushState() method](https://developer.mozilla.org/en-US/docs/Web/API/History_API#The_pushState()_method) for more information about state, title, and uri (url).
|
||||||
|
> uri and history.uri can be different.
|
||||||
|
|
||||||
|
**params**: `Object`, object containing the path parameters
|
||||||
|
|
||||||
|
# response object
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
status,
|
||||||
|
statusText,
|
||||||
|
responseText,
|
||||||
|
errorThrown,
|
||||||
|
errors
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**status**: `Number`, HTTP status 200, 404, 401, 500...
|
||||||
|
|
||||||
|
**statusText**: `String`
|
||||||
|
|
||||||
|
**responseText**: `String` response content
|
||||||
|
|
||||||
|
**errorThrown**: `Object` exception thrown (if request fails)
|
||||||
|
|
||||||
|
**errors**: `String` error description (if request fails)
|
630
frontexpress.js
630
frontexpress.js
@ -6,9 +6,9 @@ var frontexpress = (function () {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var HTTP_METHODS = ['GET', 'POST', 'PUT', 'DELETE'];
|
var HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];
|
||||||
// not supported yet
|
// not supported yet
|
||||||
// HEAD', 'CONNECT', 'OPTIONS', 'TRACE', 'PATCH';
|
// HEAD', 'CONNECT', 'OPTIONS', 'TRACE';
|
||||||
|
|
||||||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
|
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
|
||||||
return typeof obj;
|
return typeof obj;
|
||||||
@ -136,200 +136,6 @@ var toConsumableArray = function (arr) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
|
|
||||||
var Requester = function () {
|
|
||||||
function Requester() {
|
|
||||||
classCallCheck(this, Requester);
|
|
||||||
}
|
|
||||||
|
|
||||||
createClass(Requester, [{
|
|
||||||
key: 'fetch',
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make an ajax request.
|
|
||||||
*
|
|
||||||
* @param {Object} request
|
|
||||||
* @param {Function} success callback
|
|
||||||
* @param {Function} failure callback
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
|
|
||||||
value: function fetch(request, resolve, reject) {
|
|
||||||
var method = request.method,
|
|
||||||
uri = request.uri,
|
|
||||||
headers = request.headers,
|
|
||||||
data = request.data;
|
|
||||||
|
|
||||||
|
|
||||||
var success = function success(responseText) {
|
|
||||||
resolve(request, {
|
|
||||||
status: 200,
|
|
||||||
statusText: 'OK',
|
|
||||||
responseText: responseText
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var fail = function fail(_ref) {
|
|
||||||
var status = _ref.status,
|
|
||||||
statusText = _ref.statusText,
|
|
||||||
errorThrown = _ref.errorThrown;
|
|
||||||
|
|
||||||
reject(request, {
|
|
||||||
status: status,
|
|
||||||
statusText: statusText,
|
|
||||||
errorThrown: errorThrown,
|
|
||||||
errors: 'HTTP ' + status + ' ' + (statusText ? statusText : '')
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var xmlhttp = new XMLHttpRequest();
|
|
||||||
xmlhttp.onreadystatechange = function () {
|
|
||||||
if (xmlhttp.readyState === 4) {
|
|
||||||
//XMLHttpRequest.DONE
|
|
||||||
if (xmlhttp.status === 200) {
|
|
||||||
success(xmlhttp.responseText);
|
|
||||||
} else {
|
|
||||||
fail({ status: xmlhttp.status, statusText: xmlhttp.statusText });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
xmlhttp.open(method, uri, true);
|
|
||||||
if (headers) {
|
|
||||||
Object.keys(headers).forEach(function (header) {
|
|
||||||
xmlhttp.setRequestHeader(header, headers[header]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (data) {
|
|
||||||
xmlhttp.send(data);
|
|
||||||
} else {
|
|
||||||
xmlhttp.send();
|
|
||||||
}
|
|
||||||
} catch (errorThrown) {
|
|
||||||
fail({ errorThrown: errorThrown });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}]);
|
|
||||||
return Requester;
|
|
||||||
}();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Settings object.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
|
|
||||||
var Settings = function () {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the settings.
|
|
||||||
*
|
|
||||||
* - setup default configuration
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
|
|
||||||
function Settings() {
|
|
||||||
classCallCheck(this, Settings);
|
|
||||||
|
|
||||||
// default settings
|
|
||||||
this.settings = {
|
|
||||||
'http requester': new Requester(),
|
|
||||||
|
|
||||||
'http GET transformer': {
|
|
||||||
uri: function uri(_ref) {
|
|
||||||
var _uri = _ref.uri,
|
|
||||||
headers = _ref.headers,
|
|
||||||
data = _ref.data;
|
|
||||||
|
|
||||||
if (!data) {
|
|
||||||
return _uri;
|
|
||||||
}
|
|
||||||
var uriWithoutAnchor = _uri,
|
|
||||||
anchor = '';
|
|
||||||
|
|
||||||
var match = /^(.*)(#.*)$/.exec(_uri);
|
|
||||||
if (match) {
|
|
||||||
var _$exec = /^(.*)(#.*)$/.exec(_uri);
|
|
||||||
|
|
||||||
var _$exec2 = slicedToArray(_$exec, 3);
|
|
||||||
|
|
||||||
uriWithoutAnchor = _$exec2[1];
|
|
||||||
anchor = _$exec2[2];
|
|
||||||
}
|
|
||||||
uriWithoutAnchor = Object.keys(data).reduce(function (gUri, d, index) {
|
|
||||||
gUri += '' + (index === 0 && gUri.indexOf('?') === -1 ? '?' : '&') + d + '=' + data[d];
|
|
||||||
return gUri;
|
|
||||||
}, uriWithoutAnchor);
|
|
||||||
return uriWithoutAnchor + anchor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 'http POST transformer': {
|
|
||||||
// headers({uri, headers, data}) {
|
|
||||||
// if (!data) {
|
|
||||||
// return headers;
|
|
||||||
// }
|
|
||||||
// const updatedHeaders = headers || {};
|
|
||||||
// if (!updatedHeaders['Content-Type']) {
|
|
||||||
// updatedHeaders['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
||||||
// }
|
|
||||||
// return updatedHeaders;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
};
|
|
||||||
|
|
||||||
this.rules = {
|
|
||||||
'http requester': function httpRequester(requester) {
|
|
||||||
if (typeof requester.fetch !== 'function') {
|
|
||||||
throw new TypeError('setting http requester has no fetch method');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assign `setting` to `val`
|
|
||||||
*
|
|
||||||
* @param {String} setting
|
|
||||||
* @param {*} [val]
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
|
|
||||||
createClass(Settings, [{
|
|
||||||
key: 'set',
|
|
||||||
value: function set$$1(name, value) {
|
|
||||||
var checkRules = this.rules[name];
|
|
||||||
if (checkRules) {
|
|
||||||
checkRules(value);
|
|
||||||
}
|
|
||||||
this.settings[name] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return `setting`'s value.
|
|
||||||
*
|
|
||||||
* @param {String} setting
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
|
|
||||||
}, {
|
|
||||||
key: 'get',
|
|
||||||
value: function get$$1(name) {
|
|
||||||
return this.settings[name];
|
|
||||||
}
|
|
||||||
}]);
|
|
||||||
return Settings;
|
|
||||||
}();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Middleware object.
|
* Middleware object.
|
||||||
* @public
|
* @public
|
||||||
@ -361,8 +167,9 @@ var Middleware = function () {
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// entered(request) { }
|
createClass(Middleware, [{
|
||||||
|
key: 'entered',
|
||||||
|
value: function entered(request) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked by the app before a new ajax request is sent or before the DOM is unloaded.
|
* Invoked by the app before a new ajax request is sent or before the DOM is unloaded.
|
||||||
@ -374,8 +181,9 @@ var Middleware = function () {
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// exited(request) { }
|
}, {
|
||||||
|
key: 'exited',
|
||||||
|
value: function exited(request) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked by the app after an ajax request has responded or on DOM ready
|
* Invoked by the app after an ajax request has responded or on DOM ready
|
||||||
@ -389,8 +197,9 @@ var Middleware = function () {
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// updated(request, response) { }
|
}, {
|
||||||
|
key: 'updated',
|
||||||
|
value: function updated(request, response) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked by the app when an ajax request has failed.
|
* Invoked by the app when an ajax request has failed.
|
||||||
@ -401,8 +210,10 @@ var Middleware = function () {
|
|||||||
* @param {Object} response
|
* @param {Object} response
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
// failed(request, response) { }
|
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'failed',
|
||||||
|
value: function failed(request, response) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow the hand over to the next middleware object or function.
|
* Allow the hand over to the next middleware object or function.
|
||||||
@ -415,7 +226,7 @@ var Middleware = function () {
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
|
||||||
createClass(Middleware, [{
|
}, {
|
||||||
key: 'next',
|
key: 'next',
|
||||||
value: function next() {
|
value: function next() {
|
||||||
return true;
|
return true;
|
||||||
@ -538,26 +349,11 @@ var Router = function () {
|
|||||||
|
|
||||||
}, {
|
}, {
|
||||||
key: 'routes',
|
key: 'routes',
|
||||||
value: function routes(uri, method) {
|
value: function routes(application, request) {
|
||||||
|
request.params = request.params || {};
|
||||||
|
var isRouteMatch = application.get('route matcher');
|
||||||
return this._routes.filter(function (route) {
|
return this._routes.filter(function (route) {
|
||||||
if (route.method && route.method !== method) {
|
return isRouteMatch(request, route);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!route.uri || !uri) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//remove query string from uri to test
|
|
||||||
//remove anchor from uri to test
|
|
||||||
var match = /^(.*)\?.*#.*|(.*)(?=\?|#)|(.*[^\?#])$/.exec(uri);
|
|
||||||
var baseUriToCheck = match[1] || match[2] || match[3];
|
|
||||||
|
|
||||||
if (route.uri instanceof RegExp) {
|
|
||||||
return baseUriToCheck.match(route.uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
return route.uri === baseUriToCheck;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -719,6 +515,284 @@ HTTP_METHODS.forEach(function (method) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function routeMatcher(request, route) {
|
||||||
|
// check if http method are equals
|
||||||
|
if (route.method && route.method !== request.method) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// route and uri not defined always match
|
||||||
|
if (!route.uri || !request.uri) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//remove query string and anchor from uri to test
|
||||||
|
var match = /^(.*)\?.*#.*|(.*)(?=\?|#)|(.*[^\?#])$/.exec(request.uri);
|
||||||
|
var baseUriToCheck = match[1] || match[2] || match[3];
|
||||||
|
|
||||||
|
// if route is a regexp path
|
||||||
|
if (route.uri instanceof RegExp) {
|
||||||
|
return baseUriToCheck.match(route.uri) !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if route is parameterized path
|
||||||
|
if (route.uri.indexOf(':') !== -1) {
|
||||||
|
|
||||||
|
var decodeParmeterValue = function decodeParmeterValue(v) {
|
||||||
|
return !isNaN(parseFloat(v)) && isFinite(v) ? Number.isInteger(v) ? Number.parseInt(v, 10) : Number.parseFloat(v) : v;
|
||||||
|
};
|
||||||
|
|
||||||
|
// figure out key names
|
||||||
|
var keys = [];
|
||||||
|
var keysRE = /:([^\/\?]+)\??/g;
|
||||||
|
var keysMatch = keysRE.exec(route.uri);
|
||||||
|
while (keysMatch != null) {
|
||||||
|
keys.push(keysMatch[1]);
|
||||||
|
keysMatch = keysRE.exec(route.uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
// change parameterized path to regexp
|
||||||
|
var regExpUri = route.uri
|
||||||
|
// :parameter?
|
||||||
|
.replace(/\/:[^\/]+\?/g, '(?:\/([^\/]+))?')
|
||||||
|
// :parameter
|
||||||
|
.replace(/:[^\/]+/g, '([^\/]+)')
|
||||||
|
// escape all /
|
||||||
|
.replace('/', '\\/');
|
||||||
|
|
||||||
|
// checks if uri match
|
||||||
|
var routeMatch = baseUriToCheck.match(new RegExp('^' + regExpUri + '$'));
|
||||||
|
if (!routeMatch) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update params in request with keys
|
||||||
|
request.params = Object.assign(request.params, keys.reduce(function (acc, key, index) {
|
||||||
|
var value = routeMatch[index + 1];
|
||||||
|
if (value) {
|
||||||
|
value = value.indexOf(',') !== -1 ? value.split(',').map(function (v) {
|
||||||
|
return decodeParmeterValue(v);
|
||||||
|
}) : value = decodeParmeterValue(value);
|
||||||
|
}
|
||||||
|
acc[key] = value;
|
||||||
|
return acc;
|
||||||
|
}, {}));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if route is a simple path
|
||||||
|
return route.uri === baseUriToCheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Requester = function () {
|
||||||
|
function Requester() {
|
||||||
|
classCallCheck(this, Requester);
|
||||||
|
}
|
||||||
|
|
||||||
|
createClass(Requester, [{
|
||||||
|
key: 'fetch',
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make an ajax request.
|
||||||
|
*
|
||||||
|
* @param {Object} request
|
||||||
|
* @param {Function} success callback
|
||||||
|
* @param {Function} failure callback
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
value: function fetch(request, resolve, reject) {
|
||||||
|
var method = request.method,
|
||||||
|
uri = request.uri,
|
||||||
|
headers = request.headers,
|
||||||
|
data = request.data;
|
||||||
|
|
||||||
|
|
||||||
|
var success = function success(responseText) {
|
||||||
|
resolve(request, {
|
||||||
|
status: 200,
|
||||||
|
statusText: 'OK',
|
||||||
|
responseText: responseText
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var fail = function fail(_ref) {
|
||||||
|
var status = _ref.status,
|
||||||
|
statusText = _ref.statusText,
|
||||||
|
errorThrown = _ref.errorThrown;
|
||||||
|
|
||||||
|
reject(request, {
|
||||||
|
status: status,
|
||||||
|
statusText: statusText,
|
||||||
|
errorThrown: errorThrown,
|
||||||
|
errors: 'HTTP ' + status + ' ' + (statusText ? statusText : '')
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var xmlhttp = new XMLHttpRequest();
|
||||||
|
xmlhttp.onreadystatechange = function () {
|
||||||
|
if (xmlhttp.readyState === 4) {
|
||||||
|
//XMLHttpRequest.DONE
|
||||||
|
if (xmlhttp.status === 200) {
|
||||||
|
success(xmlhttp.responseText);
|
||||||
|
} else {
|
||||||
|
fail({ status: xmlhttp.status, statusText: xmlhttp.statusText });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
xmlhttp.open(method, uri, true);
|
||||||
|
if (headers) {
|
||||||
|
Object.keys(headers).forEach(function (header) {
|
||||||
|
xmlhttp.setRequestHeader(header, headers[header]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (data) {
|
||||||
|
xmlhttp.send(data);
|
||||||
|
} else {
|
||||||
|
xmlhttp.send();
|
||||||
|
}
|
||||||
|
} catch (errorThrown) {
|
||||||
|
fail({ errorThrown: errorThrown });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
return Requester;
|
||||||
|
}();
|
||||||
|
|
||||||
|
var httpGetTransformer = {
|
||||||
|
uri: function uri(_ref2) {
|
||||||
|
var _uri = _ref2.uri,
|
||||||
|
headers = _ref2.headers,
|
||||||
|
data = _ref2.data;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
return _uri;
|
||||||
|
}
|
||||||
|
var uriWithoutAnchor = _uri,
|
||||||
|
anchor = '';
|
||||||
|
|
||||||
|
var match = /^(.*)(#.*)$/.exec(_uri);
|
||||||
|
if (match) {
|
||||||
|
var _$exec = /^(.*)(#.*)$/.exec(_uri);
|
||||||
|
|
||||||
|
var _$exec2 = slicedToArray(_$exec, 3);
|
||||||
|
|
||||||
|
uriWithoutAnchor = _$exec2[1];
|
||||||
|
anchor = _$exec2[2];
|
||||||
|
}
|
||||||
|
uriWithoutAnchor = Object.keys(data).reduce(function (gUri, d, index) {
|
||||||
|
gUri += '' + (index === 0 && gUri.indexOf('?') === -1 ? '?' : '&') + d + '=' + data[d];
|
||||||
|
return gUri;
|
||||||
|
}, uriWithoutAnchor);
|
||||||
|
return uriWithoutAnchor + anchor;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// export const httpPostTransformer = {
|
||||||
|
// headers({uri, headers, data}) {
|
||||||
|
// if (!data) {
|
||||||
|
// return headers;
|
||||||
|
// }
|
||||||
|
// const updatedHeaders = headers || {};
|
||||||
|
// if (!updatedHeaders['Content-Type']) {
|
||||||
|
// updatedHeaders['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||||
|
// }
|
||||||
|
// return updatedHeaders;
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function errorIfNotFunction(toTest, message) {
|
||||||
|
if (typeof toTest !== 'function') {
|
||||||
|
throw new TypeError(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Settings object.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Settings = function () {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the settings.
|
||||||
|
*
|
||||||
|
* - setup default configuration
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function Settings() {
|
||||||
|
classCallCheck(this, Settings);
|
||||||
|
|
||||||
|
// default settings
|
||||||
|
this.settings = {
|
||||||
|
'http requester': new Requester(),
|
||||||
|
'http GET transformer': httpGetTransformer,
|
||||||
|
// 'http POST transformer': httpPostTransformer,
|
||||||
|
'route matcher': routeMatcher
|
||||||
|
};
|
||||||
|
|
||||||
|
this.rules = {
|
||||||
|
'http requester': function httpRequester(requester) {
|
||||||
|
errorIfNotFunction(requester.fetch, 'setting http requester has no fetch function');
|
||||||
|
},
|
||||||
|
'http GET transformer': function httpGETTransformer(transformer) {
|
||||||
|
if (!transformer || !transformer.uri && !transformer.headers && !transformer.data) {
|
||||||
|
throw new TypeError('setting http transformer one of functions: uri, headers, data is missing');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'route matcher': function routeMatcher$$1(_routeMatcher) {
|
||||||
|
errorIfNotFunction(_routeMatcher, 'setting route matcher is not a function');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assign `setting` to `val`
|
||||||
|
*
|
||||||
|
* @param {String} setting
|
||||||
|
* @param {*} [val]
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
createClass(Settings, [{
|
||||||
|
key: 'set',
|
||||||
|
value: function set$$1(name, value) {
|
||||||
|
var checkRules = this.rules[name];
|
||||||
|
if (checkRules) {
|
||||||
|
checkRules(value);
|
||||||
|
}
|
||||||
|
this.settings[name] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return `setting`'s value.
|
||||||
|
*
|
||||||
|
* @param {String} setting
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
}, {
|
||||||
|
key: 'get',
|
||||||
|
value: function get$$1(name) {
|
||||||
|
return this.settings[name];
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
return Settings;
|
||||||
|
}();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
* @private
|
* @private
|
||||||
@ -742,9 +816,8 @@ var Application = function () {
|
|||||||
classCallCheck(this, Application);
|
classCallCheck(this, Application);
|
||||||
|
|
||||||
this.routers = [];
|
this.routers = [];
|
||||||
// this.isDOMLoaded = false;
|
|
||||||
// this.isDOMReady = false;
|
|
||||||
this.settings = new Settings();
|
this.settings = new Settings();
|
||||||
|
this.plugins = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -763,6 +836,8 @@ var Application = function () {
|
|||||||
createClass(Application, [{
|
createClass(Application, [{
|
||||||
key: 'set',
|
key: 'set',
|
||||||
value: function set$$1() {
|
value: function set$$1() {
|
||||||
|
var _settings;
|
||||||
|
|
||||||
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
||||||
args[_key] = arguments[_key];
|
args[_key] = arguments[_key];
|
||||||
}
|
}
|
||||||
@ -773,10 +848,7 @@ var Application = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set behaviour
|
// set behaviour
|
||||||
var name = args[0],
|
(_settings = this.settings).set.apply(_settings, args);
|
||||||
value = args[1];
|
|
||||||
|
|
||||||
this.settings.set(name, value);
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -802,6 +874,12 @@ var Application = function () {
|
|||||||
value: function listen(callback) {
|
value: function listen(callback) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
|
|
||||||
|
var request = { method: 'GET', uri: window.location.pathname + window.location.search };
|
||||||
|
var response = { status: 200, statusText: 'OK' };
|
||||||
|
var currentRoutes = this._routes(request);
|
||||||
|
|
||||||
|
this._callMiddlewareMethod('entered', currentRoutes, request);
|
||||||
|
|
||||||
// manage history
|
// manage history
|
||||||
window.onpopstate = function (event) {
|
window.onpopstate = function (event) {
|
||||||
if (event.state) {
|
if (event.state) {
|
||||||
@ -809,38 +887,31 @@ var Application = function () {
|
|||||||
_request = _event$state.request,
|
_request = _event$state.request,
|
||||||
_response = _event$state.response;
|
_response = _event$state.response;
|
||||||
|
|
||||||
var _currentRoutes = _this._routes(_request.uri, _request.method);
|
['exited', 'entered', 'updated'].forEach(function (middlewareMethod) {
|
||||||
|
return _this._callMiddlewareMethod(middlewareMethod, _this._routes(_request), _request, _response);
|
||||||
_this._callMiddlewareMethod('entered', _currentRoutes, _request);
|
});
|
||||||
_this._callMiddlewareMethod('updated', _currentRoutes, _request, _response);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// manage page loading/refreshing
|
// manage page loading/refreshing
|
||||||
var request = { method: 'GET', uri: window.location.pathname + window.location.search };
|
window.onbeforeunload = function () {
|
||||||
var response = { status: 200, statusText: 'OK' };
|
_this._callMiddlewareMethod('exited');
|
||||||
var currentRoutes = this._routes();
|
};
|
||||||
|
|
||||||
var whenPageIsInteractiveFn = function whenPageIsInteractiveFn() {
|
var whenPageIsInteractiveFn = function whenPageIsInteractiveFn() {
|
||||||
|
_this.plugins.forEach(function (pluginObject) {
|
||||||
|
return pluginObject.plugin(_this);
|
||||||
|
});
|
||||||
_this._callMiddlewareMethod('updated', currentRoutes, request, response);
|
_this._callMiddlewareMethod('updated', currentRoutes, request, response);
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback(request, response);
|
callback(request, response);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.onbeforeunload = function () {
|
|
||||||
_this._callMiddlewareMethod('exited');
|
|
||||||
};
|
|
||||||
|
|
||||||
document.onreadystatechange = function () {
|
document.onreadystatechange = function () {
|
||||||
// DOM ready state
|
// DOM ready state
|
||||||
switch (document.readyState) {
|
if (document.readyState === 'interactive') {
|
||||||
case 'loading':
|
|
||||||
_this._callMiddlewareMethod('entered', currentRoutes, request);
|
|
||||||
break;
|
|
||||||
case 'interactive':
|
|
||||||
whenPageIsInteractiveFn();
|
whenPageIsInteractiveFn();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -873,6 +944,7 @@ var Application = function () {
|
|||||||
/**
|
/**
|
||||||
* Use the given middleware function or object, with optional _uri_.
|
* Use the given middleware function or object, with optional _uri_.
|
||||||
* Default _uri_ is "/".
|
* Default _uri_ is "/".
|
||||||
|
* Or use the given plugin
|
||||||
*
|
*
|
||||||
* // middleware function will be applied on path "/"
|
* // middleware function will be applied on path "/"
|
||||||
* app.use((req, res, next) => {console.log('Hello')});
|
* app.use((req, res, next) => {console.log('Hello')});
|
||||||
@ -880,8 +952,16 @@ var Application = function () {
|
|||||||
* // middleware object will be applied on path "/"
|
* // middleware object will be applied on path "/"
|
||||||
* app.use(new Middleware());
|
* app.use(new Middleware());
|
||||||
*
|
*
|
||||||
|
* // use a plugin
|
||||||
|
* app.use({
|
||||||
|
* name: 'My plugin name',
|
||||||
|
* plugin(application) {
|
||||||
|
* // here plugin implementation
|
||||||
|
* }
|
||||||
|
* });
|
||||||
|
*
|
||||||
* @param {String} uri
|
* @param {String} uri
|
||||||
* @param {Middleware|Function} middleware object or function
|
* @param {Middleware|Function|plugin} middleware object, middleware function, plugin
|
||||||
* @return {app} for chaining
|
* @return {app} for chaining
|
||||||
*
|
*
|
||||||
* @public
|
* @public
|
||||||
@ -897,8 +977,12 @@ var Application = function () {
|
|||||||
var _toParameters = toParameters(args),
|
var _toParameters = toParameters(args),
|
||||||
baseUri = _toParameters.baseUri,
|
baseUri = _toParameters.baseUri,
|
||||||
router = _toParameters.router,
|
router = _toParameters.router,
|
||||||
middleware = _toParameters.middleware;
|
middleware = _toParameters.middleware,
|
||||||
|
plugin = _toParameters.plugin;
|
||||||
|
|
||||||
|
if (plugin) {
|
||||||
|
this.plugins.push(plugin);
|
||||||
|
} else {
|
||||||
if (router) {
|
if (router) {
|
||||||
router.baseUri = baseUri;
|
router.baseUri = baseUri;
|
||||||
} else if (middleware) {
|
} else if (middleware) {
|
||||||
@ -910,6 +994,7 @@ var Application = function () {
|
|||||||
throw new TypeError('method takes at least a middleware or a router');
|
throw new TypeError('method takes at least a middleware or a router');
|
||||||
}
|
}
|
||||||
this.routers.push(router);
|
this.routers.push(router);
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -923,16 +1008,13 @@ var Application = function () {
|
|||||||
|
|
||||||
}, {
|
}, {
|
||||||
key: '_routes',
|
key: '_routes',
|
||||||
value: function _routes() {
|
value: function _routes(request) {
|
||||||
var uri = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.location.pathname + window.location.search;
|
var _this2 = this;
|
||||||
var method = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'GET';
|
|
||||||
|
|
||||||
var currentRoutes = [];
|
return this.routers.reduce(function (acc, router) {
|
||||||
this.routers.forEach(function (router) {
|
acc.push.apply(acc, toConsumableArray(router.routes(_this2, request)));
|
||||||
currentRoutes.push.apply(currentRoutes, toConsumableArray(router.routes(uri, method)));
|
return acc;
|
||||||
});
|
}, []);
|
||||||
|
|
||||||
return currentRoutes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -992,7 +1074,7 @@ var Application = function () {
|
|||||||
}, {
|
}, {
|
||||||
key: '_fetch',
|
key: '_fetch',
|
||||||
value: function _fetch(req, resolve, reject) {
|
value: function _fetch(req, resolve, reject) {
|
||||||
var _this2 = this;
|
var _this3 = this;
|
||||||
|
|
||||||
var method = req.method,
|
var method = req.method,
|
||||||
uri = req.uri,
|
uri = req.uri,
|
||||||
@ -1007,16 +1089,16 @@ var Application = function () {
|
|||||||
_headersFn = httpMethodTransformer.headers,
|
_headersFn = httpMethodTransformer.headers,
|
||||||
_dataFn = httpMethodTransformer.data;
|
_dataFn = httpMethodTransformer.data;
|
||||||
|
|
||||||
uri = _uriFn ? _uriFn({ uri: uri, headers: headers, data: data }) : uri;
|
req.uri = _uriFn ? _uriFn({ uri: uri, headers: headers, data: data }) : uri;
|
||||||
headers = _headersFn ? _headersFn({ uri: uri, headers: headers, data: data }) : headers;
|
req.headers = _headersFn ? _headersFn({ uri: uri, headers: headers, data: data }) : headers;
|
||||||
data = _dataFn ? _dataFn({ uri: uri, headers: headers, data: data }) : data;
|
req.data = _dataFn ? _dataFn({ uri: uri, headers: headers, data: data }) : data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calls middleware exited method
|
// calls middleware exited method
|
||||||
this._callMiddlewareMethod('exited');
|
this._callMiddlewareMethod('exited');
|
||||||
|
|
||||||
// gathers all routes impacted by the uri
|
// gathers all routes impacted by the uri
|
||||||
var currentRoutes = this._routes(uri, method);
|
var currentRoutes = this._routes(req);
|
||||||
|
|
||||||
// calls middleware entered method
|
// calls middleware entered method
|
||||||
this._callMiddlewareMethod('entered', currentRoutes, req);
|
this._callMiddlewareMethod('entered', currentRoutes, req);
|
||||||
@ -1026,12 +1108,12 @@ var Application = function () {
|
|||||||
if (history) {
|
if (history) {
|
||||||
window.history.pushState({ request: request, response: response }, history.title, history.uri);
|
window.history.pushState({ request: request, response: response }, history.title, history.uri);
|
||||||
}
|
}
|
||||||
_this2._callMiddlewareMethod('updated', currentRoutes, request, response);
|
_this3._callMiddlewareMethod('updated', currentRoutes, request, response);
|
||||||
if (resolve) {
|
if (resolve) {
|
||||||
resolve(request, response);
|
resolve(request, response);
|
||||||
}
|
}
|
||||||
}, function (request, response) {
|
}, function (request, response) {
|
||||||
_this2._callMiddlewareMethod('failed', currentRoutes, request, response);
|
_this3._callMiddlewareMethod('failed', currentRoutes, request, response);
|
||||||
if (reject) {
|
if (reject) {
|
||||||
reject(request, response);
|
reject(request, response);
|
||||||
}
|
}
|
||||||
@ -1133,29 +1215,25 @@ HTTP_METHODS.reduce(function (reqProto, method) {
|
|||||||
}, Application.prototype);
|
}, Application.prototype);
|
||||||
|
|
||||||
function toParameters(args) {
|
function toParameters(args) {
|
||||||
|
var _args, _args2, _args3, _args4;
|
||||||
|
|
||||||
var baseUri = void 0,
|
var baseUri = void 0,
|
||||||
middleware = void 0,
|
middleware = void 0,
|
||||||
router = void 0,
|
router = void 0,
|
||||||
|
plugin = void 0,
|
||||||
which = void 0;
|
which = void 0;
|
||||||
if (args && args.length > 0) {
|
|
||||||
if (args.length === 1) {
|
|
||||||
var _args = slicedToArray(args, 1);
|
|
||||||
|
|
||||||
which = _args[0];
|
args.length === 1 ? (_args = args, _args2 = slicedToArray(_args, 1), which = _args2[0], _args) : (_args3 = args, _args4 = slicedToArray(_args3, 2), baseUri = _args4[0], which = _args4[1], _args3);
|
||||||
} else {
|
|
||||||
var _args2 = slicedToArray(args, 2);
|
|
||||||
|
|
||||||
baseUri = _args2[0];
|
|
||||||
which = _args2[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (which instanceof Router) {
|
if (which instanceof Router) {
|
||||||
router = which;
|
router = which;
|
||||||
} else if (which instanceof Middleware || typeof which === 'function') {
|
} else if (which instanceof Middleware || typeof which === 'function') {
|
||||||
middleware = which;
|
middleware = which;
|
||||||
|
} else if (which && which.plugin && typeof which.plugin === 'function') {
|
||||||
|
plugin = which;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return { baseUri: baseUri, middleware: middleware, router: router, which: which };
|
return { baseUri: baseUri, middleware: middleware, router: router, plugin: plugin, which: which };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
2
frontexpress.min.js
vendored
2
frontexpress.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -26,9 +26,8 @@ export default class Application {
|
|||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.routers = [];
|
this.routers = [];
|
||||||
// this.isDOMLoaded = false;
|
|
||||||
// this.isDOMReady = false;
|
|
||||||
this.settings = new Settings();
|
this.settings = new Settings();
|
||||||
|
this.plugins = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -52,8 +51,7 @@ export default class Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set behaviour
|
// set behaviour
|
||||||
const [name, value] = args;
|
this.settings.set(...args);
|
||||||
this.settings.set(name, value);
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -76,43 +74,41 @@ export default class Application {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
listen(callback) {
|
listen(callback) {
|
||||||
|
const request = {method: 'GET', uri: window.location.pathname + window.location.search};
|
||||||
|
const response = {status: 200, statusText: 'OK'};
|
||||||
|
const currentRoutes = this._routes(request);
|
||||||
|
|
||||||
|
this._callMiddlewareMethod('entered', currentRoutes, request);
|
||||||
|
|
||||||
// manage history
|
// manage history
|
||||||
window.onpopstate = (event) => {
|
window.onpopstate = (event) => {
|
||||||
if (event.state) {
|
if (event.state) {
|
||||||
const {request, response} = event.state;
|
const {request, response} = event.state;
|
||||||
const currentRoutes = this._routes(request.uri, request.method);
|
[
|
||||||
|
'exited',
|
||||||
this._callMiddlewareMethod('entered', currentRoutes, request);
|
'entered',
|
||||||
this._callMiddlewareMethod('updated', currentRoutes, request, response);
|
'updated'
|
||||||
|
].forEach(middlewareMethod => this._callMiddlewareMethod(middlewareMethod, this._routes(request), request, response));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// manage page loading/refreshing
|
// manage page loading/refreshing
|
||||||
const request = {method: 'GET', uri: window.location.pathname + window.location.search};
|
window.onbeforeunload = () => {
|
||||||
const response = {status: 200, statusText: 'OK'};
|
this._callMiddlewareMethod('exited');
|
||||||
const currentRoutes = this._routes();
|
};
|
||||||
|
|
||||||
const whenPageIsInteractiveFn = () => {
|
const whenPageIsInteractiveFn = () => {
|
||||||
|
this.plugins.forEach(pluginObject => pluginObject.plugin(this));
|
||||||
this._callMiddlewareMethod('updated', currentRoutes, request, response);
|
this._callMiddlewareMethod('updated', currentRoutes, request, response);
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback(request, response);
|
callback(request, response);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.onbeforeunload = () => {
|
|
||||||
this._callMiddlewareMethod('exited');
|
|
||||||
};
|
|
||||||
|
|
||||||
document.onreadystatechange = () => {
|
document.onreadystatechange = () => {
|
||||||
// DOM ready state
|
// DOM ready state
|
||||||
switch (document.readyState) {
|
if (document.readyState === 'interactive') {
|
||||||
case 'loading':
|
|
||||||
this._callMiddlewareMethod('entered', currentRoutes, request);
|
|
||||||
break;
|
|
||||||
case 'interactive':
|
|
||||||
whenPageIsInteractiveFn();
|
whenPageIsInteractiveFn();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -145,6 +141,7 @@ export default class Application {
|
|||||||
/**
|
/**
|
||||||
* Use the given middleware function or object, with optional _uri_.
|
* Use the given middleware function or object, with optional _uri_.
|
||||||
* Default _uri_ is "/".
|
* Default _uri_ is "/".
|
||||||
|
* Or use the given plugin
|
||||||
*
|
*
|
||||||
* // middleware function will be applied on path "/"
|
* // middleware function will be applied on path "/"
|
||||||
* app.use((req, res, next) => {console.log('Hello')});
|
* app.use((req, res, next) => {console.log('Hello')});
|
||||||
@ -152,15 +149,26 @@ export default class Application {
|
|||||||
* // middleware object will be applied on path "/"
|
* // middleware object will be applied on path "/"
|
||||||
* app.use(new Middleware());
|
* app.use(new Middleware());
|
||||||
*
|
*
|
||||||
|
* // use a plugin
|
||||||
|
* app.use({
|
||||||
|
* name: 'My plugin name',
|
||||||
|
* plugin(application) {
|
||||||
|
* // here plugin implementation
|
||||||
|
* }
|
||||||
|
* });
|
||||||
|
*
|
||||||
* @param {String} uri
|
* @param {String} uri
|
||||||
* @param {Middleware|Function} middleware object or function
|
* @param {Middleware|Function|plugin} middleware object, middleware function, plugin
|
||||||
* @return {app} for chaining
|
* @return {app} for chaining
|
||||||
*
|
*
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use(...args) {
|
use(...args) {
|
||||||
let {baseUri, router, middleware} = toParameters(args);
|
let {baseUri, router, middleware, plugin} = toParameters(args);
|
||||||
|
if (plugin) {
|
||||||
|
this.plugins.push(plugin);
|
||||||
|
} else {
|
||||||
if (router) {
|
if (router) {
|
||||||
router.baseUri = baseUri;
|
router.baseUri = baseUri;
|
||||||
} else if (middleware) {
|
} else if (middleware) {
|
||||||
@ -172,6 +180,7 @@ export default class Application {
|
|||||||
throw new TypeError('method takes at least a middleware or a router');
|
throw new TypeError('method takes at least a middleware or a router');
|
||||||
}
|
}
|
||||||
this.routers.push(router);
|
this.routers.push(router);
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -184,13 +193,11 @@ export default class Application {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
_routes(uri=window.location.pathname + window.location.search, method='GET') {
|
_routes(request) {
|
||||||
const currentRoutes = [];
|
return this.routers.reduce((acc, router) => {
|
||||||
this.routers.forEach((router) => {
|
acc.push(...router.routes(this, request));
|
||||||
currentRoutes.push(...router.routes(uri, method));
|
return acc;
|
||||||
});
|
}, []);
|
||||||
|
|
||||||
return currentRoutes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -253,16 +260,16 @@ export default class Application {
|
|||||||
const httpMethodTransformer = this.get(`http ${method} transformer`);
|
const httpMethodTransformer = this.get(`http ${method} transformer`);
|
||||||
if (httpMethodTransformer) {
|
if (httpMethodTransformer) {
|
||||||
const {uri: _uriFn, headers: _headersFn, data: _dataFn } = httpMethodTransformer;
|
const {uri: _uriFn, headers: _headersFn, data: _dataFn } = httpMethodTransformer;
|
||||||
uri = _uriFn ? _uriFn({uri, headers, data}) : uri;
|
req.uri = _uriFn ? _uriFn({uri, headers, data}) : uri;
|
||||||
headers = _headersFn ? _headersFn({uri, headers, data}) : headers;
|
req.headers = _headersFn ? _headersFn({uri, headers, data}) : headers;
|
||||||
data = _dataFn ? _dataFn({uri, headers, data}) : data;
|
req.data = _dataFn ? _dataFn({uri, headers, data}) : data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calls middleware exited method
|
// calls middleware exited method
|
||||||
this._callMiddlewareMethod('exited');
|
this._callMiddlewareMethod('exited');
|
||||||
|
|
||||||
// gathers all routes impacted by the uri
|
// gathers all routes impacted by the uri
|
||||||
const currentRoutes = this._routes(uri, method);
|
const currentRoutes = this._routes(req);
|
||||||
|
|
||||||
// calls middleware entered method
|
// calls middleware entered method
|
||||||
this._callMiddlewareMethod('entered', currentRoutes, req);
|
this._callMiddlewareMethod('entered', currentRoutes, req);
|
||||||
@ -369,19 +376,17 @@ HTTP_METHODS.reduce((reqProto, method) => {
|
|||||||
|
|
||||||
|
|
||||||
export function toParameters(args) {
|
export function toParameters(args) {
|
||||||
let baseUri, middleware, router, which;
|
let baseUri, middleware, router, plugin, which;
|
||||||
if (args && args.length > 0) {
|
|
||||||
if (args.length === 1) {
|
args.length === 1 ? [which,] = args : [baseUri, which,] = args;
|
||||||
[which,] = args;
|
|
||||||
} else {
|
|
||||||
[baseUri, which,] = args;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (which instanceof Router) {
|
if (which instanceof Router) {
|
||||||
router = which;
|
router = which;
|
||||||
} else if ((which instanceof Middleware) || (typeof which === 'function')) {
|
} else if (which instanceof Middleware || typeof which === 'function') {
|
||||||
middleware = which;
|
middleware = which;
|
||||||
|
} else if(which && which.plugin && typeof which.plugin === 'function') {
|
||||||
|
plugin = which;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return {baseUri, middleware, router, which};
|
return {baseUri, middleware, router, plugin, which};
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default ['GET', 'POST', 'PUT', 'DELETE'];
|
export default ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];
|
||||||
// not supported yet
|
// not supported yet
|
||||||
// HEAD', 'CONNECT', 'OPTIONS', 'TRACE', 'PATCH';
|
// HEAD', 'CONNECT', 'OPTIONS', 'TRACE';
|
||||||
|
@ -27,7 +27,7 @@ export default class Middleware {
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// entered(request) { }
|
entered(request) { }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,7 +40,7 @@ export default class Middleware {
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// exited(request) { }
|
exited(request) { }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,7 +55,7 @@ export default class Middleware {
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// updated(request, response) { }
|
updated(request, response) { }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -67,7 +67,7 @@ export default class Middleware {
|
|||||||
* @param {Object} response
|
* @param {Object} response
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
// failed(request, response) { }
|
failed(request, response) { }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,3 +67,34 @@ export default class Requester {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const httpGetTransformer = {
|
||||||
|
uri({uri, headers, data}) {
|
||||||
|
if (!data) {
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
let [uriWithoutAnchor, anchor] = [uri, ''];
|
||||||
|
const match = /^(.*)(#.*)$/.exec(uri);
|
||||||
|
if (match) {
|
||||||
|
[,uriWithoutAnchor, anchor] = /^(.*)(#.*)$/.exec(uri);
|
||||||
|
}
|
||||||
|
uriWithoutAnchor = Object.keys(data).reduce((gUri, d, index) => {
|
||||||
|
gUri += `${(index === 0 && gUri.indexOf('?') === -1)?'?':'&'}${d}=${data[d]}`;
|
||||||
|
return gUri;
|
||||||
|
}, uriWithoutAnchor);
|
||||||
|
return uriWithoutAnchor + anchor;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// export const httpPostTransformer = {
|
||||||
|
// headers({uri, headers, data}) {
|
||||||
|
// if (!data) {
|
||||||
|
// return headers;
|
||||||
|
// }
|
||||||
|
// const updatedHeaders = headers || {};
|
||||||
|
// if (!updatedHeaders['Content-Type']) {
|
||||||
|
// updatedHeaders['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||||
|
// }
|
||||||
|
// return updatedHeaders;
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
@ -135,26 +135,11 @@ export default class Router {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
routes(uri, method) {
|
routes(application, request) {
|
||||||
|
request.params = request.params || {};
|
||||||
|
const isRouteMatch = application.get('route matcher');
|
||||||
return this._routes.filter((route) => {
|
return this._routes.filter((route) => {
|
||||||
if (route.method && route.method !== method) {
|
return isRouteMatch(request, route);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!route.uri || !uri) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//remove query string from uri to test
|
|
||||||
//remove anchor from uri to test
|
|
||||||
const match = /^(.*)\?.*#.*|(.*)(?=\?|#)|(.*[^\?#])$/.exec(uri);
|
|
||||||
const baseUriToCheck = match[1] || match[2] || match[3];
|
|
||||||
|
|
||||||
if (route.uri instanceof RegExp) {
|
|
||||||
return baseUriToCheck.match(route.uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
return route.uri === baseUriToCheck;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,3 +252,71 @@ HTTP_METHODS.forEach((method) => {
|
|||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export function routeMatcher(request, route) {
|
||||||
|
// check if http method are equals
|
||||||
|
if (route.method && route.method !== request.method) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// route and uri not defined always match
|
||||||
|
if (!route.uri || !request.uri) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//remove query string and anchor from uri to test
|
||||||
|
const match = /^(.*)\?.*#.*|(.*)(?=\?|#)|(.*[^\?#])$/.exec(request.uri);
|
||||||
|
const baseUriToCheck = match[1] || match[2] || match[3];
|
||||||
|
|
||||||
|
// if route is a regexp path
|
||||||
|
if (route.uri instanceof RegExp) {
|
||||||
|
return baseUriToCheck.match(route.uri) !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if route is parameterized path
|
||||||
|
if (route.uri.indexOf(':') !== -1) {
|
||||||
|
|
||||||
|
const decodeParmeterValue = (v) => {
|
||||||
|
return !isNaN(parseFloat(v)) && isFinite(v) ? (Number.isInteger(v) ? Number.parseInt(v, 10) : Number.parseFloat(v)) : v;
|
||||||
|
};
|
||||||
|
|
||||||
|
// figure out key names
|
||||||
|
const keys = [];
|
||||||
|
const keysRE = /:([^\/\?]+)\??/g;
|
||||||
|
let keysMatch = keysRE.exec(route.uri);
|
||||||
|
while (keysMatch != null) {
|
||||||
|
keys.push(keysMatch[1]);
|
||||||
|
keysMatch = keysRE.exec(route.uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
// change parameterized path to regexp
|
||||||
|
const regExpUri = route.uri
|
||||||
|
// :parameter?
|
||||||
|
.replace(/\/:[^\/]+\?/g, '(?:\/([^\/]+))?')
|
||||||
|
// :parameter
|
||||||
|
.replace(/:[^\/]+/g, '([^\/]+)')
|
||||||
|
// escape all /
|
||||||
|
.replace('/', '\\/');
|
||||||
|
|
||||||
|
// checks if uri match
|
||||||
|
const routeMatch = baseUriToCheck.match(new RegExp(`^${regExpUri}$`));
|
||||||
|
if (!routeMatch) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update params in request with keys
|
||||||
|
request.params = Object.assign(request.params, keys.reduce((acc, key, index) => {
|
||||||
|
let value = routeMatch[index + 1];
|
||||||
|
if (value) {
|
||||||
|
value = value.indexOf(',') !== -1 ? value.split(',').map(v => decodeParmeterValue(v)) : value = decodeParmeterValue(value);
|
||||||
|
}
|
||||||
|
acc[key] = value;
|
||||||
|
return acc;
|
||||||
|
}, {}));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if route is a simple path
|
||||||
|
return route.uri === baseUriToCheck;
|
||||||
|
}
|
||||||
|
@ -2,9 +2,15 @@
|
|||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
import {routeMatcher} from './router';
|
||||||
|
import Requester, {httpGetTransformer} from './requester';
|
||||||
|
|
||||||
import Requester from './requester';
|
|
||||||
|
|
||||||
|
function errorIfNotFunction(toTest, message) {
|
||||||
|
if(typeof toTest !== 'function') {
|
||||||
|
throw new TypeError(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Settings object.
|
* Settings object.
|
||||||
@ -26,43 +32,22 @@ export default class Settings {
|
|||||||
// default settings
|
// default settings
|
||||||
this.settings = {
|
this.settings = {
|
||||||
'http requester': new Requester(),
|
'http requester': new Requester(),
|
||||||
|
'http GET transformer': httpGetTransformer,
|
||||||
'http GET transformer': {
|
// 'http POST transformer': httpPostTransformer,
|
||||||
uri({uri, headers, data}) {
|
'route matcher': routeMatcher
|
||||||
if (!data) {
|
|
||||||
return uri;
|
|
||||||
}
|
|
||||||
let [uriWithoutAnchor, anchor] = [uri, ''];
|
|
||||||
const match = /^(.*)(#.*)$/.exec(uri);
|
|
||||||
if (match) {
|
|
||||||
[,uriWithoutAnchor, anchor] = /^(.*)(#.*)$/.exec(uri);
|
|
||||||
}
|
|
||||||
uriWithoutAnchor = Object.keys(data).reduce((gUri, d, index) => {
|
|
||||||
gUri += `${(index === 0 && gUri.indexOf('?') === -1)?'?':'&'}${d}=${data[d]}`;
|
|
||||||
return gUri;
|
|
||||||
}, uriWithoutAnchor);
|
|
||||||
return uriWithoutAnchor + anchor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 'http POST transformer': {
|
|
||||||
// headers({uri, headers, data}) {
|
|
||||||
// if (!data) {
|
|
||||||
// return headers;
|
|
||||||
// }
|
|
||||||
// const updatedHeaders = headers || {};
|
|
||||||
// if (!updatedHeaders['Content-Type']) {
|
|
||||||
// updatedHeaders['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
||||||
// }
|
|
||||||
// return updatedHeaders;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.rules = {
|
this.rules = {
|
||||||
'http requester': (requester) => {
|
'http requester': (requester) => {
|
||||||
if(typeof requester.fetch !== 'function') {
|
errorIfNotFunction(requester.fetch , 'setting http requester has no fetch function');
|
||||||
throw new TypeError('setting http requester has no fetch method');
|
},
|
||||||
|
'http GET transformer': (transformer) => {
|
||||||
|
if (!transformer || (!transformer.uri && !transformer.headers && !transformer.data)) {
|
||||||
|
throw new TypeError('setting http transformer one of functions: uri, headers, data is missing');
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
'route matcher': (routeMatcher) => {
|
||||||
|
errorIfNotFunction(routeMatcher, 'setting route matcher is not a function');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
34
package.json
34
package.json
@ -1,15 +1,16 @@
|
|||||||
{
|
{
|
||||||
"name": "frontexpress",
|
"name": "frontexpress",
|
||||||
"version": "1.0.1",
|
"version": "1.2.0",
|
||||||
"description": "Frontexpress manages routes in browser like ExpressJS on Node",
|
"description": "Frontexpress manages routes in browser like ExpressJS on Node",
|
||||||
"main": "dist/frontexpress.js",
|
"main": "dist/frontexpress.js",
|
||||||
|
"jsnext:main": "lib/frontexpress.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"only-test": "mocha --compilers js:babel-core/register",
|
"test-only": "mocha --compilers js:babel-core/register",
|
||||||
"test": "npm run lint && babel-node node_modules/.bin/babel-istanbul cover node_modules/.bin/_mocha",
|
"test": "npm run lint && babel-node node_modules/.bin/babel-istanbul cover node_modules/.bin/_mocha",
|
||||||
"gzipsize": "babel-node gzipsize.js",
|
"gzipsize": "babel-node gzipsize.js",
|
||||||
"frontpackage": "rollup -c rollup.config.dev.js && rollup -c rollup.config.prod.js && npm run gzipsize",
|
"frontpackage": "rollup -c rollup.config.dev.js && rollup -c rollup.config.prod.js && npm run gzipsize",
|
||||||
"prepublish": "rimraf dist && babel lib -d dist"
|
"prepublish": "rimraf dist && babel lib -d dist && npm run frontpackage"
|
||||||
},
|
},
|
||||||
"author": "Camel Aissani <camel.aissani@gmail.com> (https://nuageprive.fr)",
|
"author": "Camel Aissani <camel.aissani@gmail.com> (https://nuageprive.fr)",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -33,23 +34,28 @@
|
|||||||
"babel-core": "^6.21.0",
|
"babel-core": "^6.21.0",
|
||||||
"babel-eslint": "^7.1.1",
|
"babel-eslint": "^7.1.1",
|
||||||
"babel-istanbul": "^0.12.1",
|
"babel-istanbul": "^0.12.1",
|
||||||
"babel-plugin-add-module-exports": "^0.2.1",
|
|
||||||
"babel-preset-babili": "0.0.9",
|
|
||||||
"babel-preset-es2015": "^6.18.0",
|
"babel-preset-es2015": "^6.18.0",
|
||||||
"babel-preset-es2015-rollup": "^3.0.0",
|
"babel-preset-es2015-rollup": "^3.0.0",
|
||||||
"babel-register": "^6.18.0",
|
"babel-register": "^6.18.0",
|
||||||
"bytesize": "^0.2.0",
|
"bytesize": "^0.2.0",
|
||||||
"chai": "^3.5.0",
|
"chai": "^4.*",
|
||||||
"eslint": "^3.12.2",
|
"eslint": "^3.*",
|
||||||
"eslint-loader": "^1.6.1",
|
|
||||||
"expose-loader": "^0.7.1",
|
|
||||||
"istanbul": "^0.4.5",
|
"istanbul": "^0.4.5",
|
||||||
"mocha": "^3.2.0",
|
"mocha": "^3.2.0",
|
||||||
"rimraf": "^2.5.4",
|
"rimraf": "^2.5.4",
|
||||||
"rollup": "^0.38.3",
|
"rollup": "^0.*",
|
||||||
"rollup-plugin-babel": "^2.7.1",
|
"rollup-plugin-babel": "^2.7.1",
|
||||||
"rollup-plugin-uglify": "^1.0.1",
|
"rollup-plugin-uglify-es": "0.0.1",
|
||||||
"sinon": "^1.17.6",
|
"sinon": "^1.*"
|
||||||
"uglify-js": "github:mishoo/UglifyJS2#harmony"
|
},
|
||||||
}
|
"files": [
|
||||||
|
"dist/",
|
||||||
|
"docs/",
|
||||||
|
"lib/",
|
||||||
|
"README.md",
|
||||||
|
"LICENCE",
|
||||||
|
"frontexpress.js",
|
||||||
|
"frontexpress.min.js",
|
||||||
|
"frontexpress.min.js.map"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import uglify from 'rollup-plugin-uglify';
|
import uglify from 'rollup-plugin-uglify-es';
|
||||||
import { minify } from 'uglify-js';
|
|
||||||
import babel from 'rollup-plugin-babel';
|
import babel from 'rollup-plugin-babel';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -13,13 +12,6 @@ export default {
|
|||||||
babelrc: false,
|
babelrc: false,
|
||||||
presets: ['es2015-rollup']
|
presets: ['es2015-rollup']
|
||||||
}),
|
}),
|
||||||
uglify({
|
uglify()
|
||||||
compress: {
|
|
||||||
warnings: false,
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
comments: false
|
|
||||||
}
|
|
||||||
}, minify)
|
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
@ -989,4 +989,22 @@ describe('Application', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('plugin management', () => {
|
||||||
|
it('setup a plugin', (done) => {
|
||||||
|
const app = frontexpress();
|
||||||
|
app.use({
|
||||||
|
name: 'my plugin',
|
||||||
|
plugin(application) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen();
|
||||||
|
|
||||||
|
//simulate readystatechange
|
||||||
|
document.readyState = 'interactive';
|
||||||
|
document.onreadystatechange();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
20
test/middleware-test.js
Normal file
20
test/middleware-test.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/*eslint-env mocha*/
|
||||||
|
import {assert} from 'chai';
|
||||||
|
import Middleware from '../lib/middleware';
|
||||||
|
|
||||||
|
describe('Middleware', () => {
|
||||||
|
it('check exposed methods', () => {
|
||||||
|
const middleware = new Middleware();
|
||||||
|
assert(middleware.entered);
|
||||||
|
assert(middleware.exited);
|
||||||
|
assert(middleware.updated);
|
||||||
|
assert(middleware.failed);
|
||||||
|
assert(middleware.next);
|
||||||
|
|
||||||
|
middleware.entered();
|
||||||
|
middleware.exited();
|
||||||
|
middleware.updated();
|
||||||
|
middleware.failed();
|
||||||
|
assert(middleware.next());
|
||||||
|
});
|
||||||
|
});
|
@ -4,6 +4,9 @@ import sinon from 'sinon';
|
|||||||
import frontexpress from '../lib/frontexpress';
|
import frontexpress from '../lib/frontexpress';
|
||||||
import HTTP_METHODS from '../lib/methods';
|
import HTTP_METHODS from '../lib/methods';
|
||||||
|
|
||||||
|
const application = frontexpress();
|
||||||
|
const routeMatcher = application.get('route matcher');
|
||||||
|
|
||||||
describe('Router', () => {
|
describe('Router', () => {
|
||||||
|
|
||||||
describe('generated methods', () => {
|
describe('generated methods', () => {
|
||||||
@ -12,6 +15,7 @@ describe('Router', () => {
|
|||||||
assert(typeof router.all === 'function');
|
assert(typeof router.all === 'function');
|
||||||
assert(typeof router.get === 'function');
|
assert(typeof router.get === 'function');
|
||||||
assert(typeof router.put === 'function');
|
assert(typeof router.put === 'function');
|
||||||
|
assert(typeof router.patch === 'function');
|
||||||
assert(typeof router.post === 'function');
|
assert(typeof router.post === 'function');
|
||||||
assert(typeof router.delete === 'function');
|
assert(typeof router.delete === 'function');
|
||||||
});
|
});
|
||||||
@ -46,7 +50,7 @@ describe('Router', () => {
|
|||||||
|
|
||||||
router.get(middleware);
|
router.get(middleware);
|
||||||
|
|
||||||
const r1 = router.routes('/', 'GET');
|
const r1 = router.routes(application, {uri: '/', method: 'GET'});
|
||||||
assert(r1.length === 1);
|
assert(r1.length === 1);
|
||||||
assert(r1[0].uri === undefined);
|
assert(r1[0].uri === undefined);
|
||||||
assert(r1[0].method === 'GET');
|
assert(r1[0].method === 'GET');
|
||||||
@ -64,37 +68,37 @@ describe('Router', () => {
|
|||||||
.post('/route2', middleware2)
|
.post('/route2', middleware2)
|
||||||
.all('/route3', middleware3);
|
.all('/route3', middleware3);
|
||||||
|
|
||||||
const r1 = router.routes('/route1', 'GET');
|
const r1 = router.routes(application, {uri: '/route1', method: 'GET'});
|
||||||
assert(r1.length === 1);
|
assert(r1.length === 1);
|
||||||
assert(r1[0].uri === '/route1');
|
assert(r1[0].uri === '/route1');
|
||||||
assert(r1[0].method === 'GET');
|
assert(r1[0].method === 'GET');
|
||||||
assert(r1[0].middleware === middleware1);
|
assert(r1[0].middleware === middleware1);
|
||||||
|
|
||||||
const r2 = router.routes('/route2', 'POST');
|
const r2 = router.routes(application, {uri: '/route2', method: 'POST'});
|
||||||
assert(r2.length === 1);
|
assert(r2.length === 1);
|
||||||
assert(r2[0].uri === '/route2');
|
assert(r2[0].uri === '/route2');
|
||||||
assert(r2[0].method === 'POST');
|
assert(r2[0].method === 'POST');
|
||||||
assert(r2[0].middleware === middleware2);
|
assert(r2[0].middleware === middleware2);
|
||||||
|
|
||||||
let r3 = router.routes('/route3', 'GET');
|
let r3 = router.routes(application, {uri: '/route3', method: 'GET'});
|
||||||
assert(r3.length === 1);
|
assert(r3.length === 1);
|
||||||
assert(r3[0].uri === '/route3');
|
assert(r3[0].uri === '/route3');
|
||||||
assert(r3[0].method === 'GET');
|
assert(r3[0].method === 'GET');
|
||||||
assert(r3[0].middleware === middleware3);
|
assert(r3[0].middleware === middleware3);
|
||||||
|
|
||||||
r3 = router.routes('/route3', 'POST');
|
r3 = router.routes(application, {uri: '/route3', method: 'POST'});
|
||||||
assert(r3.length === 1);
|
assert(r3.length === 1);
|
||||||
assert(r3[0].uri === '/route3');
|
assert(r3[0].uri === '/route3');
|
||||||
assert(r3[0].method === 'POST');
|
assert(r3[0].method === 'POST');
|
||||||
assert(r3[0].middleware === middleware3);
|
assert(r3[0].middleware === middleware3);
|
||||||
|
|
||||||
r3 = router.routes('/route3', 'PUT');
|
r3 = router.routes(application, {uri: '/route3', method: 'PUT'});
|
||||||
assert(r3.length === 1);
|
assert(r3.length === 1);
|
||||||
assert(r3[0].uri === '/route3');
|
assert(r3[0].uri === '/route3');
|
||||||
assert(r3[0].method === 'PUT');
|
assert(r3[0].method === 'PUT');
|
||||||
assert(r3[0].middleware === middleware3);
|
assert(r3[0].middleware === middleware3);
|
||||||
|
|
||||||
r3 = router.routes('/route3', 'DELETE');
|
r3 = router.routes(application, {uri: '/route3', method: 'DELETE'});
|
||||||
assert(r3.length === 1);
|
assert(r3.length === 1);
|
||||||
assert(r3[0].uri === '/route3');
|
assert(r3[0].uri === '/route3');
|
||||||
assert(r3[0].method === 'DELETE');
|
assert(r3[0].method === 'DELETE');
|
||||||
@ -107,7 +111,7 @@ describe('Router', () => {
|
|||||||
|
|
||||||
router.get(/^\/route1/, middleware);
|
router.get(/^\/route1/, middleware);
|
||||||
|
|
||||||
const r = router.routes('/route1', 'GET');
|
const r = router.routes(application, {uri: '/route1', method: 'GET'});
|
||||||
assert(r.length === 1);
|
assert(r.length === 1);
|
||||||
assert(r[0].uri instanceof RegExp);
|
assert(r[0].uri instanceof RegExp);
|
||||||
assert(r[0].uri.toString() === new RegExp('^\/route1').toString());
|
assert(r[0].uri.toString() === new RegExp('^\/route1').toString());
|
||||||
@ -120,7 +124,7 @@ describe('Router', () => {
|
|||||||
|
|
||||||
router.get('/subroute', new frontexpress.Middleware());
|
router.get('/subroute', new frontexpress.Middleware());
|
||||||
|
|
||||||
const r = router.routes('/route1/subroute', 'GET');
|
const r = router.routes(application, {uri: '/route1/subroute', method: 'GET'});
|
||||||
assert(r.length === 1);
|
assert(r.length === 1);
|
||||||
assert(r[0].uri === '/route1/subroute');
|
assert(r[0].uri === '/route1/subroute');
|
||||||
});
|
});
|
||||||
@ -130,7 +134,7 @@ describe('Router', () => {
|
|||||||
|
|
||||||
router.get(new frontexpress.Middleware());
|
router.get(new frontexpress.Middleware());
|
||||||
|
|
||||||
const r = router.routes('/route1', 'GET');
|
const r = router.routes(application, {uri: '/route1', method: 'GET'});
|
||||||
assert(r.length === 1);
|
assert(r.length === 1);
|
||||||
assert(r[0].uri === '/route1');
|
assert(r[0].uri === '/route1');
|
||||||
});
|
});
|
||||||
@ -140,7 +144,7 @@ describe('Router', () => {
|
|||||||
|
|
||||||
router.get('/subroute', new frontexpress.Middleware());
|
router.get('/subroute', new frontexpress.Middleware());
|
||||||
|
|
||||||
const r = router.routes('/route1/subroute', 'GET');
|
const r = router.routes(application, {uri: '/route1/subroute', method: 'GET'});
|
||||||
assert(r.length === 1);
|
assert(r.length === 1);
|
||||||
assert(r[0].uri === '/route1/subroute');
|
assert(r[0].uri === '/route1/subroute');
|
||||||
});
|
});
|
||||||
@ -150,7 +154,7 @@ describe('Router', () => {
|
|||||||
|
|
||||||
router.get('/subroute ', new frontexpress.Middleware());
|
router.get('/subroute ', new frontexpress.Middleware());
|
||||||
|
|
||||||
let r = router.routes('/route1/subroute', 'GET');
|
let r = router.routes(application, {uri: '/route1/subroute', method: 'GET'});
|
||||||
assert(r.length === 1);
|
assert(r.length === 1);
|
||||||
assert(r[0].uri === '/route1/subroute');
|
assert(r[0].uri === '/route1/subroute');
|
||||||
|
|
||||||
@ -160,7 +164,7 @@ describe('Router', () => {
|
|||||||
|
|
||||||
router.get(new frontexpress.Middleware());
|
router.get(new frontexpress.Middleware());
|
||||||
|
|
||||||
r = router.routes('/route1', 'GET');
|
r = router.routes(application, {uri: '/route1', method: 'GET'});
|
||||||
assert(r.length === 1);
|
assert(r.length === 1);
|
||||||
assert(r[0].uri === '/route1');
|
assert(r[0].uri === '/route1');
|
||||||
});
|
});
|
||||||
@ -170,7 +174,7 @@ describe('Router', () => {
|
|||||||
|
|
||||||
router.get('/subroute', new frontexpress.Middleware());
|
router.get('/subroute', new frontexpress.Middleware());
|
||||||
|
|
||||||
let r = router.routes('/route1/subroute?a=b&c=d', 'GET');
|
let r = router.routes(application, {uri: '/route1/subroute?a=b&c=d', method: 'GET'});
|
||||||
assert(r.length === 1);
|
assert(r.length === 1);
|
||||||
assert(r[0].uri === '/route1/subroute');
|
assert(r[0].uri === '/route1/subroute');
|
||||||
assert(r[0].data === undefined);
|
assert(r[0].data === undefined);
|
||||||
@ -181,7 +185,7 @@ describe('Router', () => {
|
|||||||
|
|
||||||
router.get('/subroute', new frontexpress.Middleware());
|
router.get('/subroute', new frontexpress.Middleware());
|
||||||
|
|
||||||
let r = router.routes('/route1/subroute#a=b&c=d', 'GET');
|
let r = router.routes(application, {uri: '/route1/subroute#a=b&c=d', method: 'GET'});
|
||||||
assert(r.length === 1);
|
assert(r.length === 1);
|
||||||
assert(r[0].uri === '/route1/subroute');
|
assert(r[0].uri === '/route1/subroute');
|
||||||
assert(r[0].data === undefined);
|
assert(r[0].data === undefined);
|
||||||
@ -192,7 +196,7 @@ describe('Router', () => {
|
|||||||
|
|
||||||
router.get('/subroute', new frontexpress.Middleware());
|
router.get('/subroute', new frontexpress.Middleware());
|
||||||
|
|
||||||
let r = router.routes('/route1/subroute?a=b&c=d#anchor1', 'GET');
|
let r = router.routes(application, {uri: '/route1/subroute?a=b&c=d#anchor1', method: 'GET'});
|
||||||
assert(r.length === 1);
|
assert(r.length === 1);
|
||||||
assert(r[0].uri === '/route1/subroute');
|
assert(r[0].uri === '/route1/subroute');
|
||||||
assert(r[0].data === undefined);
|
assert(r[0].data === undefined);
|
||||||
@ -264,7 +268,7 @@ describe('Router', () => {
|
|||||||
|
|
||||||
router.get(middleware);
|
router.get(middleware);
|
||||||
|
|
||||||
const r = router.routes('/', 'GET');
|
const r = router.routes(application, {uri: '/', method: 'GET'});
|
||||||
assert(r.length === 1);
|
assert(r.length === 1);
|
||||||
assert(r[0].uri === '/');
|
assert(r[0].uri === '/');
|
||||||
assert(r[0].method === 'GET');
|
assert(r[0].method === 'GET');
|
||||||
@ -277,7 +281,7 @@ describe('Router', () => {
|
|||||||
|
|
||||||
router.get('/route1', middleware);
|
router.get('/route1', middleware);
|
||||||
|
|
||||||
const r = router.routes('/route1', 'GET');
|
const r = router.routes(application, {uri: '/route1', method: 'GET'});
|
||||||
assert(r.length === 1);
|
assert(r.length === 1);
|
||||||
assert(r[0].uri === '/route1');
|
assert(r[0].uri === '/route1');
|
||||||
assert(r[0].method === 'GET');
|
assert(r[0].method === 'GET');
|
||||||
@ -295,7 +299,7 @@ describe('Router', () => {
|
|||||||
const middleware = new frontexpress.Middleware();
|
const middleware = new frontexpress.Middleware();
|
||||||
router.get(middleware);
|
router.get(middleware);
|
||||||
|
|
||||||
const r = router.routes('/part1', 'GET');
|
const r = router.routes(application, {uri: '/part1', method: 'GET'});
|
||||||
assert(r.length === 1);
|
assert(r.length === 1);
|
||||||
assert(r[0].uri instanceof RegExp);
|
assert(r[0].uri instanceof RegExp);
|
||||||
assert(r[0].uri.toString() === new RegExp('^\/part').toString());
|
assert(r[0].uri.toString() === new RegExp('^\/part').toString());
|
||||||
@ -303,4 +307,113 @@ describe('Router', () => {
|
|||||||
assert(r[0].middleware === middleware);
|
assert(r[0].middleware === middleware);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('check route matcher', () => {
|
||||||
|
it('/', () => {
|
||||||
|
const route = {uri: '/', method: 'GET'};
|
||||||
|
|
||||||
|
const request = {uri: '/', method: 'GET', params: {}};
|
||||||
|
assert(routeMatcher(request, route));
|
||||||
|
assert.deepEqual(request.params, {});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('/a/b/c', () => {
|
||||||
|
const route = {uri: '/a/b/c', method: 'GET'};
|
||||||
|
|
||||||
|
let request = {uri: '/a/b/c', method: 'GET', params: {}};
|
||||||
|
assert(routeMatcher(request, route));
|
||||||
|
assert.deepEqual(request.params, {});
|
||||||
|
|
||||||
|
request = {uri: '/a/b/c/', method: 'GET', params: {}};
|
||||||
|
assert.strictEqual(routeMatcher(request, route), false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('/^\//', () => {
|
||||||
|
const route = {uri: /^\//, method: 'GET'};
|
||||||
|
|
||||||
|
const request = {uri: '/a/b/c', method: 'GET', params: {}};
|
||||||
|
assert(routeMatcher(request, route));
|
||||||
|
assert.deepEqual(request.params, {});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('/:id', () => {
|
||||||
|
const route = {uri: '/:id', method: 'GET'};
|
||||||
|
|
||||||
|
const request = {uri: '/1000', method: 'GET', params: {}};
|
||||||
|
assert(routeMatcher(request, route));
|
||||||
|
assert.strictEqual(request.params.id, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('/user/:id', () => {
|
||||||
|
const route = {uri: '/user/:id', method: 'GET'};
|
||||||
|
|
||||||
|
let request = {uri: '/user/1000', method: 'GET', params: {}};
|
||||||
|
assert(routeMatcher(request, route));
|
||||||
|
assert.strictEqual(request.params.id, 1000);
|
||||||
|
|
||||||
|
request = {uri: '/user/100.2122', method: 'GET', params: {}};
|
||||||
|
assert(routeMatcher(request, route));
|
||||||
|
assert.strictEqual(request.params.id, 100.2122);
|
||||||
|
|
||||||
|
request = {uri: '/user', method: 'GET', params: {}};
|
||||||
|
assert.strictEqual(routeMatcher(request, route), false);
|
||||||
|
|
||||||
|
request = {uri: '/user/', method: 'GET', params: {}};
|
||||||
|
assert.strictEqual(routeMatcher(request, route), false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('/user/:id with id as coma separated values', () => {
|
||||||
|
const route = {uri: '/user/:id', method: 'GET'};
|
||||||
|
|
||||||
|
let request = {uri: '/user/1,2,3', method: 'GET', params: {}};
|
||||||
|
assert(routeMatcher(request, route));
|
||||||
|
assert.deepEqual(request.params, {id: [1,2,3]});
|
||||||
|
|
||||||
|
request = {uri: '/user/1.5,2.55,4.25', method: 'GET', params: {}};
|
||||||
|
assert(routeMatcher(request, route));
|
||||||
|
assert.deepEqual(request.params, {id: [1.5,2.55,4.25]});
|
||||||
|
|
||||||
|
request = {uri: '/user/a,b,c', method: 'GET', params: {}};
|
||||||
|
assert(routeMatcher(request, route));
|
||||||
|
assert.deepEqual(request.params, {id: ['a','b','c']});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('/user/:id?', () => {
|
||||||
|
const route = {uri: '/user/:id?', method: 'GET'};
|
||||||
|
|
||||||
|
let request = {uri: '/user/1000', method: 'GET', params: {}};
|
||||||
|
assert(routeMatcher(request, route));
|
||||||
|
assert.strictEqual(request.params.id, 1000);
|
||||||
|
|
||||||
|
request = {uri: '/user', method: 'GET', params: {}};
|
||||||
|
assert.strictEqual(routeMatcher(request, route), true);
|
||||||
|
assert.deepEqual(request.params, {id: undefined});
|
||||||
|
|
||||||
|
request = {uri: '/user/', method: 'GET', params: {}};
|
||||||
|
assert.strictEqual(routeMatcher(request, route), false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('/user/:firstname/:lastname', () => {
|
||||||
|
const route = {uri: '/user/:firstname/:lastname', method: 'GET'};
|
||||||
|
|
||||||
|
let request = {uri: '/user/camel/aissani', method: 'GET', params: {}};
|
||||||
|
assert(routeMatcher(request, route));
|
||||||
|
assert.deepEqual(request.params, {firstname: 'camel', lastname:'aissani'} );
|
||||||
|
|
||||||
|
request = {uri: '/user/camel', method: 'GET', params: {}};
|
||||||
|
assert.strictEqual(routeMatcher(request, route), false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('/user/:firstname?/:lastname', () => {
|
||||||
|
const route = {uri: '/user/:firstname?/:lastname', method: 'GET'};
|
||||||
|
|
||||||
|
let request = {uri: '/user/camel/aissani', method: 'GET', params: {}};
|
||||||
|
assert(routeMatcher(request, route));
|
||||||
|
assert.deepEqual(request.params, {firstname: 'camel', lastname:'aissani'} );
|
||||||
|
|
||||||
|
request = {uri: '/user/aissani', method: 'GET', params: {}};
|
||||||
|
assert(routeMatcher(request, route));
|
||||||
|
assert.deepEqual(request.params, {firstname: undefined, lastname:'aissani'} );
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,11 +1,43 @@
|
|||||||
/*eslint-env mocha*/
|
/*eslint-env mocha*/
|
||||||
import {assert} from 'chai';
|
import chai, {assert} from 'chai';
|
||||||
import Settings from '../lib/settings';
|
import Settings from '../lib/settings';
|
||||||
|
|
||||||
describe('Settings', () => {
|
describe('Settings', () => {
|
||||||
const settings = new Settings();
|
const settings = new Settings();
|
||||||
|
|
||||||
describe('http GET method transformer', () => {
|
describe('http GET method transformer', () => {
|
||||||
|
it('check setting rule', () => {
|
||||||
|
const defaultHttpGetTransformer = settings.get('http GET transformer');
|
||||||
|
|
||||||
|
chai.expect(() => settings.set('http GET transformer', null)).to.throw(TypeError);
|
||||||
|
chai.expect(() => settings.set('http GET transformer', {})).to.throw(TypeError);
|
||||||
|
chai.expect(() => settings.set('http GET transformer', {foo:()=>{}})).to.throw(TypeError);
|
||||||
|
|
||||||
|
const uri = () => {};
|
||||||
|
settings.set('http GET transformer', {uri});
|
||||||
|
assert.deepEqual(settings.get('http GET transformer'), {uri});
|
||||||
|
|
||||||
|
const headers = () => {};
|
||||||
|
settings.set('http GET transformer', {headers});
|
||||||
|
assert.deepEqual(settings.get('http GET transformer'), {headers});
|
||||||
|
|
||||||
|
const data = () => {};
|
||||||
|
settings.set('http GET transformer', {data});
|
||||||
|
assert.deepEqual(settings.get('http GET transformer'), {data});
|
||||||
|
|
||||||
|
settings.set('http GET transformer', defaultHttpGetTransformer);
|
||||||
|
|
||||||
|
|
||||||
|
const defaultRouteMatcher = settings.get('route matcher');
|
||||||
|
chai.expect(() => settings.set('route matcher', null)).to.throw(TypeError);
|
||||||
|
chai.expect(() => settings.set('route matcher', {})).to.throw(TypeError);
|
||||||
|
chai.expect(() => settings.set('route matcher', 1)).to.throw(TypeError);
|
||||||
|
|
||||||
|
const routeMatcher = () => {};
|
||||||
|
settings.set('route matcher', routeMatcher);
|
||||||
|
assert.strictEqual(settings.get('route matcher'), routeMatcher);
|
||||||
|
});
|
||||||
|
|
||||||
it('simple uri', () => {
|
it('simple uri', () => {
|
||||||
const uriFn = settings.get('http GET transformer').uri;
|
const uriFn = settings.get('http GET transformer').uri;
|
||||||
const dataFn = settings.get('http GET transformer').data;
|
const dataFn = settings.get('http GET transformer').data;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user