mirror of
https://gitlab.silvrtree.co.uk/martind2000/frontexpress.git
synced 2025-01-10 21:45:08 +00:00
parent
34b7580d18
commit
a1e56dc6c3
269
README.md
269
README.md
@ -1,38 +1,14 @@
|
||||
![frontexpress](http://fontmeme.com/embed.php?text=frontexpress&name=Atype%201%20Light.ttf&size=90&style_color=6F6F75)
|
||||
|
||||
Code the front-end like on the back-end with [ExpressJS](http://expressjs.com/)
|
||||
|
||||
[frontexpress demo](https://github.com/camelaissani/frontexpress-demo) repository.
|
||||
|
||||
[![Build Status](https://travis-ci.org/camelaissani/frontexpress.svg?branch=master)](https://travis-ci.org/camelaissani/frontexpress)
|
||||
[![Code Climate](https://codeclimate.com/github/camelaissani/frontexpress/badges/gpa.svg)](https://codeclimate.com/github/camelaissani/frontexpress)
|
||||
[![Coverage Status](https://coveralls.io/repos/github/camelaissani/frontexpress/badge.svg?branch=master)](https://coveralls.io/github/camelaissani/frontexpress?branch=master)
|
||||
![dependencies](https://img.shields.io/gemnasium/mathiasbynens/he.svg)
|
||||
![Size Shield](https://img.shields.io/badge/size-2.86kb-brightgreen.svg)
|
||||
|
||||
Frontexpress manages routes in browser like [ExpressJS](http://expressjs.com/) does on Node.
|
||||
|
||||
Same language same API on all the stack.
|
||||
|
||||
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
|
||||
});
|
||||
```
|
||||
![Size Shield](https://img.shields.io/badge/size-3.26kb-brightgreen.svg)
|
||||
|
||||
## Installation
|
||||
|
||||
@ -52,43 +28,31 @@ $ bower install frontexpress
|
||||
|
||||
On [jsDelivr](https://cdn.jsdelivr.net/npm/frontexpress@1.1.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
|
||||
$ git clone git@github.com:camelaissani/frontexpress.git
|
||||
$ cd frontexpress
|
||||
// front-end logic on navigation path "/page2"
|
||||
app.get('/page2', (req, res) => {
|
||||
document.querySelector('.content').innerHTML = res.responseText;
|
||||
});
|
||||
|
||||
// start front-end application
|
||||
app.listen();
|
||||
```
|
||||
|
||||
Install the dependencies and run the test suite:
|
||||
### Routes
|
||||
|
||||
```bash
|
||||
$ 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:
|
||||
Listen GET requests on path /hello:
|
||||
|
||||
```js
|
||||
app.get('/hello', (req, res) => {
|
||||
@ -96,7 +60,7 @@ app.get('/hello', (req, res) => {
|
||||
});
|
||||
```
|
||||
|
||||
Listen a POST request on path /item:
|
||||
Listen POST requests on path /item:
|
||||
|
||||
```js
|
||||
app.post('/item', (req, res) => {
|
||||
@ -104,9 +68,7 @@ app.post('/item', (req, res) => {
|
||||
});
|
||||
```
|
||||
|
||||
### Routing based on RegExp
|
||||
|
||||
Listen navigation on paths which start with /api/:
|
||||
Listen GET requests on path starting with /api/:
|
||||
|
||||
```js
|
||||
app.get(/^api\//, (req, res) => {
|
||||
@ -114,6 +76,66 @@ 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]
|
||||
});
|
||||
```
|
||||
### 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
|
||||
|
||||
You can provide multiple handlers functions on a navigation path. Invoking ```next()``` function allows to chain the handlers.
|
||||
@ -138,7 +160,7 @@ h2!
|
||||
|
||||
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()```.
|
||||
|
||||
@ -149,7 +171,7 @@ app.route('/book')
|
||||
.put((req, res) => { console.log('Update the book') });
|
||||
```
|
||||
|
||||
### frontexpress.Router
|
||||
#### frontexpress.Router
|
||||
|
||||
Use the ```frontexpress.Router``` class to create modular, mountable route handlers.
|
||||
|
||||
@ -187,121 +209,24 @@ import birds from './birds';
|
||||
app.use('/birds', birds);
|
||||
```
|
||||
|
||||
## API
|
||||
## [API](https://github.com/camelaissani/frontexpress/blob/master/docs/api.md)
|
||||
|
||||
| | 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|
|
||||
## Tests
|
||||
|
||||
Clone the git repository:
|
||||
|
||||
### middleware function
|
||||
|
||||
After registering a middleware function, the application invokes it with these parameters:
|
||||
|
||||
```js
|
||||
(request, response, next) => {
|
||||
next();
|
||||
}
|
||||
```bash
|
||||
$ git clone git@github.com:camelaissani/frontexpress.git
|
||||
$ cd frontexpress
|
||||
```
|
||||
|
||||
**request**: `Object`, the ajax request information sent by the app
|
||||
Install the dependencies and run the test suite:
|
||||
|
||||
**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
|
||||
}
|
||||
}
|
||||
```bash
|
||||
$ npm install
|
||||
$ npm test
|
||||
```
|
||||
|
||||
**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.
|
||||
|
||||
|
||||
### 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)
|
||||
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
||||
|
||||
|
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)
|
621
frontexpress.js
621
frontexpress.js
@ -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.
|
||||
* @public
|
||||
@ -543,26 +349,11 @@ var Router = function () {
|
||||
|
||||
}, {
|
||||
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) {
|
||||
if (route.method && route.method !== method) {
|
||||
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;
|
||||
return isRouteMatch(request, route);
|
||||
});
|
||||
}
|
||||
|
||||
@ -724,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.
|
||||
* @private
|
||||
@ -747,9 +816,8 @@ var Application = function () {
|
||||
classCallCheck(this, Application);
|
||||
|
||||
this.routers = [];
|
||||
// this.isDOMLoaded = false;
|
||||
// this.isDOMReady = false;
|
||||
this.settings = new Settings();
|
||||
this.plugins = [];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -768,6 +836,8 @@ var Application = function () {
|
||||
createClass(Application, [{
|
||||
key: 'set',
|
||||
value: function set$$1() {
|
||||
var _settings;
|
||||
|
||||
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
||||
args[_key] = arguments[_key];
|
||||
}
|
||||
@ -778,10 +848,7 @@ var Application = function () {
|
||||
}
|
||||
|
||||
// set behaviour
|
||||
var name = args[0],
|
||||
value = args[1];
|
||||
|
||||
this.settings.set(name, value);
|
||||
(_settings = this.settings).set.apply(_settings, args);
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -807,6 +874,12 @@ var Application = function () {
|
||||
value: function listen(callback) {
|
||||
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
|
||||
window.onpopstate = function (event) {
|
||||
if (event.state) {
|
||||
@ -814,32 +887,27 @@ var Application = function () {
|
||||
_request = _event$state.request,
|
||||
_response = _event$state.response;
|
||||
|
||||
var _currentRoutes = _this._routes(_request.uri, _request.method);
|
||||
|
||||
_this._callMiddlewareMethod('exited');
|
||||
_this._callMiddlewareMethod('entered', _currentRoutes, _request);
|
||||
_this._callMiddlewareMethod('updated', _currentRoutes, _request, _response);
|
||||
['exited', 'entered', 'updated'].forEach(function (middlewareMethod) {
|
||||
return _this._callMiddlewareMethod(middlewareMethod, _this._routes(_request), _request, _response);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// manage page loading/refreshing
|
||||
var request = { method: 'GET', uri: window.location.pathname + window.location.search };
|
||||
var response = { status: 200, statusText: 'OK' };
|
||||
var currentRoutes = this._routes();
|
||||
window.onbeforeunload = function () {
|
||||
_this._callMiddlewareMethod('exited');
|
||||
};
|
||||
|
||||
var whenPageIsInteractiveFn = function whenPageIsInteractiveFn() {
|
||||
_this.plugins.forEach(function (pluginObject) {
|
||||
return pluginObject.plugin(_this);
|
||||
});
|
||||
_this._callMiddlewareMethod('updated', currentRoutes, request, response);
|
||||
if (callback) {
|
||||
callback(request, response);
|
||||
}
|
||||
};
|
||||
|
||||
window.onbeforeunload = function () {
|
||||
_this._callMiddlewareMethod('exited');
|
||||
};
|
||||
|
||||
this._callMiddlewareMethod('entered', currentRoutes, request);
|
||||
|
||||
document.onreadystatechange = function () {
|
||||
// DOM ready state
|
||||
if (document.readyState === 'interactive') {
|
||||
@ -876,6 +944,7 @@ var Application = function () {
|
||||
/**
|
||||
* Use the given middleware function or object, with optional _uri_.
|
||||
* Default _uri_ is "/".
|
||||
* Or use the given plugin
|
||||
*
|
||||
* // middleware function will be applied on path "/"
|
||||
* app.use((req, res, next) => {console.log('Hello')});
|
||||
@ -883,8 +952,16 @@ var Application = function () {
|
||||
* // middleware object will be applied on path "/"
|
||||
* app.use(new Middleware());
|
||||
*
|
||||
* // use a plugin
|
||||
* app.use({
|
||||
* name: 'My plugin name',
|
||||
* plugin(application) {
|
||||
* // here plugin implementation
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* @param {String} uri
|
||||
* @param {Middleware|Function} middleware object or function
|
||||
* @param {Middleware|Function|plugin} middleware object, middleware function, plugin
|
||||
* @return {app} for chaining
|
||||
*
|
||||
* @public
|
||||
@ -900,19 +977,24 @@ var Application = function () {
|
||||
var _toParameters = toParameters(args),
|
||||
baseUri = _toParameters.baseUri,
|
||||
router = _toParameters.router,
|
||||
middleware = _toParameters.middleware;
|
||||
middleware = _toParameters.middleware,
|
||||
plugin = _toParameters.plugin;
|
||||
|
||||
if (router) {
|
||||
router.baseUri = baseUri;
|
||||
} else if (middleware) {
|
||||
router = new Router(baseUri);
|
||||
HTTP_METHODS.forEach(function (method) {
|
||||
router[method.toLowerCase()](middleware);
|
||||
});
|
||||
if (plugin) {
|
||||
this.plugins.push(plugin);
|
||||
} else {
|
||||
throw new TypeError('method takes at least a middleware or a router');
|
||||
if (router) {
|
||||
router.baseUri = baseUri;
|
||||
} else if (middleware) {
|
||||
router = new Router(baseUri);
|
||||
HTTP_METHODS.forEach(function (method) {
|
||||
router[method.toLowerCase()](middleware);
|
||||
});
|
||||
} else {
|
||||
throw new TypeError('method takes at least a middleware or a router');
|
||||
}
|
||||
this.routers.push(router);
|
||||
}
|
||||
this.routers.push(router);
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -926,16 +1008,13 @@ var Application = function () {
|
||||
|
||||
}, {
|
||||
key: '_routes',
|
||||
value: function _routes() {
|
||||
var uri = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.location.pathname + window.location.search;
|
||||
var method = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'GET';
|
||||
value: function _routes(request) {
|
||||
var _this2 = this;
|
||||
|
||||
var currentRoutes = [];
|
||||
this.routers.forEach(function (router) {
|
||||
currentRoutes.push.apply(currentRoutes, toConsumableArray(router.routes(uri, method)));
|
||||
});
|
||||
|
||||
return currentRoutes;
|
||||
return this.routers.reduce(function (acc, router) {
|
||||
acc.push.apply(acc, toConsumableArray(router.routes(_this2, request)));
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -995,7 +1074,7 @@ var Application = function () {
|
||||
}, {
|
||||
key: '_fetch',
|
||||
value: function _fetch(req, resolve, reject) {
|
||||
var _this2 = this;
|
||||
var _this3 = this;
|
||||
|
||||
var method = req.method,
|
||||
uri = req.uri,
|
||||
@ -1019,7 +1098,7 @@ var Application = function () {
|
||||
this._callMiddlewareMethod('exited');
|
||||
|
||||
// gathers all routes impacted by the uri
|
||||
var currentRoutes = this._routes(uri, method);
|
||||
var currentRoutes = this._routes(req);
|
||||
|
||||
// calls middleware entered method
|
||||
this._callMiddlewareMethod('entered', currentRoutes, req);
|
||||
@ -1029,12 +1108,12 @@ var Application = function () {
|
||||
if (history) {
|
||||
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) {
|
||||
resolve(request, response);
|
||||
}
|
||||
}, function (request, response) {
|
||||
_this2._callMiddlewareMethod('failed', currentRoutes, request, response);
|
||||
_this3._callMiddlewareMethod('failed', currentRoutes, request, response);
|
||||
if (reject) {
|
||||
reject(request, response);
|
||||
}
|
||||
@ -1136,29 +1215,25 @@ HTTP_METHODS.reduce(function (reqProto, method) {
|
||||
}, Application.prototype);
|
||||
|
||||
function toParameters(args) {
|
||||
var _args, _args2, _args3, _args4;
|
||||
|
||||
var baseUri = void 0,
|
||||
middleware = void 0,
|
||||
router = void 0,
|
||||
plugin = void 0,
|
||||
which = void 0;
|
||||
if (args && args.length > 0) {
|
||||
if (args.length === 1) {
|
||||
var _args = slicedToArray(args, 1);
|
||||
|
||||
which = _args[0];
|
||||
} else {
|
||||
var _args2 = slicedToArray(args, 2);
|
||||
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);
|
||||
|
||||
baseUri = _args2[0];
|
||||
which = _args2[1];
|
||||
}
|
||||
|
||||
if (which instanceof Router) {
|
||||
router = which;
|
||||
} else if (which instanceof Middleware || typeof which === 'function') {
|
||||
middleware = which;
|
||||
}
|
||||
if (which instanceof Router) {
|
||||
router = which;
|
||||
} else if (which instanceof Middleware || typeof which === 'function') {
|
||||
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() {
|
||||
this.routers = [];
|
||||
// this.isDOMLoaded = false;
|
||||
// this.isDOMReady = false;
|
||||
this.settings = new Settings();
|
||||
this.plugins = [];
|
||||
}
|
||||
|
||||
|
||||
@ -52,8 +51,7 @@ export default class Application {
|
||||
}
|
||||
|
||||
// set behaviour
|
||||
const [name, value] = args;
|
||||
this.settings.set(name, value);
|
||||
this.settings.set(...args);
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -76,37 +74,37 @@ export default class Application {
|
||||
*/
|
||||
|
||||
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
|
||||
window.onpopstate = (event) => {
|
||||
if (event.state) {
|
||||
const {request, response} = event.state;
|
||||
const currentRoutes = this._routes(request.uri, request.method);
|
||||
|
||||
this._callMiddlewareMethod('exited');
|
||||
this._callMiddlewareMethod('entered', currentRoutes, request);
|
||||
this._callMiddlewareMethod('updated', currentRoutes, request, response);
|
||||
[
|
||||
'exited',
|
||||
'entered',
|
||||
'updated'
|
||||
].forEach(middlewareMethod => this._callMiddlewareMethod(middlewareMethod, this._routes(request), request, response));
|
||||
}
|
||||
};
|
||||
|
||||
// manage page loading/refreshing
|
||||
const request = {method: 'GET', uri: window.location.pathname + window.location.search};
|
||||
const response = {status: 200, statusText: 'OK'};
|
||||
const currentRoutes = this._routes();
|
||||
window.onbeforeunload = () => {
|
||||
this._callMiddlewareMethod('exited');
|
||||
};
|
||||
|
||||
const whenPageIsInteractiveFn = () => {
|
||||
this.plugins.forEach(pluginObject => pluginObject.plugin(this));
|
||||
this._callMiddlewareMethod('updated', currentRoutes, request, response);
|
||||
if (callback) {
|
||||
callback(request, response);
|
||||
}
|
||||
};
|
||||
|
||||
window.onbeforeunload = () => {
|
||||
this._callMiddlewareMethod('exited');
|
||||
};
|
||||
|
||||
this._callMiddlewareMethod('entered', currentRoutes, request);
|
||||
|
||||
document.onreadystatechange = () => {
|
||||
// DOM ready state
|
||||
if (document.readyState === 'interactive') {
|
||||
@ -117,7 +115,6 @@ export default class Application {
|
||||
if (['interactive', 'complete'].indexOf(document.readyState) !== -1) {
|
||||
whenPageIsInteractiveFn();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -144,6 +141,7 @@ export default class Application {
|
||||
/**
|
||||
* Use the given middleware function or object, with optional _uri_.
|
||||
* Default _uri_ is "/".
|
||||
* Or use the given plugin
|
||||
*
|
||||
* // middleware function will be applied on path "/"
|
||||
* app.use((req, res, next) => {console.log('Hello')});
|
||||
@ -151,26 +149,38 @@ export default class Application {
|
||||
* // middleware object will be applied on path "/"
|
||||
* app.use(new Middleware());
|
||||
*
|
||||
* // use a plugin
|
||||
* app.use({
|
||||
* name: 'My plugin name',
|
||||
* plugin(application) {
|
||||
* // here plugin implementation
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* @param {String} uri
|
||||
* @param {Middleware|Function} middleware object or function
|
||||
* @param {Middleware|Function|plugin} middleware object, middleware function, plugin
|
||||
* @return {app} for chaining
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
use(...args) {
|
||||
let {baseUri, router, middleware} = toParameters(args);
|
||||
if (router) {
|
||||
router.baseUri = baseUri;
|
||||
} else if (middleware) {
|
||||
router = new Router(baseUri);
|
||||
HTTP_METHODS.forEach((method) => {
|
||||
router[method.toLowerCase()](middleware);
|
||||
});
|
||||
let {baseUri, router, middleware, plugin} = toParameters(args);
|
||||
if (plugin) {
|
||||
this.plugins.push(plugin);
|
||||
} else {
|
||||
throw new TypeError('method takes at least a middleware or a router');
|
||||
if (router) {
|
||||
router.baseUri = baseUri;
|
||||
} else if (middleware) {
|
||||
router = new Router(baseUri);
|
||||
HTTP_METHODS.forEach((method) => {
|
||||
router[method.toLowerCase()](middleware);
|
||||
});
|
||||
} else {
|
||||
throw new TypeError('method takes at least a middleware or a router');
|
||||
}
|
||||
this.routers.push(router);
|
||||
}
|
||||
this.routers.push(router);
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -183,13 +193,11 @@ export default class Application {
|
||||
* @private
|
||||
*/
|
||||
|
||||
_routes(uri=window.location.pathname + window.location.search, method='GET') {
|
||||
const currentRoutes = [];
|
||||
this.routers.forEach((router) => {
|
||||
currentRoutes.push(...router.routes(uri, method));
|
||||
});
|
||||
|
||||
return currentRoutes;
|
||||
_routes(request) {
|
||||
return this.routers.reduce((acc, router) => {
|
||||
acc.push(...router.routes(this, request));
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
|
||||
|
||||
@ -261,7 +269,7 @@ export default class Application {
|
||||
this._callMiddlewareMethod('exited');
|
||||
|
||||
// gathers all routes impacted by the uri
|
||||
const currentRoutes = this._routes(uri, method);
|
||||
const currentRoutes = this._routes(req);
|
||||
|
||||
// calls middleware entered method
|
||||
this._callMiddlewareMethod('entered', currentRoutes, req);
|
||||
@ -368,19 +376,17 @@ HTTP_METHODS.reduce((reqProto, method) => {
|
||||
|
||||
|
||||
export function toParameters(args) {
|
||||
let baseUri, middleware, router, which;
|
||||
if (args && args.length > 0) {
|
||||
if (args.length === 1) {
|
||||
[which,] = args;
|
||||
} else {
|
||||
[baseUri, which,] = args;
|
||||
}
|
||||
let baseUri, middleware, router, plugin, which;
|
||||
|
||||
if (which instanceof Router) {
|
||||
router = which;
|
||||
} else if ((which instanceof Middleware) || (typeof which === 'function')) {
|
||||
middleware = which;
|
||||
}
|
||||
args.length === 1 ? [which,] = args : [baseUri, which,] = args;
|
||||
|
||||
if (which instanceof Router) {
|
||||
router = which;
|
||||
} else if (which instanceof Middleware || typeof which === 'function') {
|
||||
middleware = which;
|
||||
} else if(which && which.plugin && typeof which.plugin === 'function') {
|
||||
plugin = which;
|
||||
}
|
||||
return {baseUri, middleware, router, which};
|
||||
|
||||
return {baseUri, middleware, router, plugin, which};
|
||||
}
|
||||
|
@ -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
|
||||
*/
|
||||
|
||||
routes(uri, method) {
|
||||
routes(application, request) {
|
||||
request.params = request.params || {};
|
||||
const isRouteMatch = application.get('route matcher');
|
||||
return this._routes.filter((route) => {
|
||||
if (route.method && route.method !== method) {
|
||||
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;
|
||||
return isRouteMatch(request, route);
|
||||
});
|
||||
}
|
||||
|
||||
@ -267,3 +252,71 @@ HTTP_METHODS.forEach((method) => {
|
||||
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.
|
||||
* @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.
|
||||
@ -26,43 +32,22 @@ export default class Settings {
|
||||
// default settings
|
||||
this.settings = {
|
||||
'http requester': new Requester(),
|
||||
|
||||
'http GET transformer': {
|
||||
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;
|
||||
}
|
||||
}
|
||||
// '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;
|
||||
// }
|
||||
// }
|
||||
'http GET transformer': httpGetTransformer,
|
||||
// 'http POST transformer': httpPostTransformer,
|
||||
'route matcher': routeMatcher
|
||||
};
|
||||
|
||||
this.rules = {
|
||||
'http requester': (requester) => {
|
||||
if(typeof requester.fetch !== 'function') {
|
||||
throw new TypeError('setting http requester has no fetch method');
|
||||
errorIfNotFunction(requester.fetch , 'setting http requester has no fetch function');
|
||||
},
|
||||
'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');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "frontexpress",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.0",
|
||||
"description": "Frontexpress manages routes in browser like ExpressJS on Node",
|
||||
"main": "dist/frontexpress.js",
|
||||
"jsnext:main": "lib/frontexpress.js",
|
||||
|
@ -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 HTTP_METHODS from '../lib/methods';
|
||||
|
||||
const application = frontexpress();
|
||||
const routeMatcher = application.get('route matcher');
|
||||
|
||||
describe('Router', () => {
|
||||
|
||||
describe('generated methods', () => {
|
||||
@ -12,6 +15,7 @@ describe('Router', () => {
|
||||
assert(typeof router.all === 'function');
|
||||
assert(typeof router.get === 'function');
|
||||
assert(typeof router.put === 'function');
|
||||
assert(typeof router.patch === 'function');
|
||||
assert(typeof router.post === 'function');
|
||||
assert(typeof router.delete === 'function');
|
||||
});
|
||||
@ -46,7 +50,7 @@ describe('Router', () => {
|
||||
|
||||
router.get(middleware);
|
||||
|
||||
const r1 = router.routes('/', 'GET');
|
||||
const r1 = router.routes(application, {uri: '/', method: 'GET'});
|
||||
assert(r1.length === 1);
|
||||
assert(r1[0].uri === undefined);
|
||||
assert(r1[0].method === 'GET');
|
||||
@ -64,37 +68,37 @@ describe('Router', () => {
|
||||
.post('/route2', middleware2)
|
||||
.all('/route3', middleware3);
|
||||
|
||||
const r1 = router.routes('/route1', 'GET');
|
||||
const r1 = router.routes(application, {uri: '/route1', method: 'GET'});
|
||||
assert(r1.length === 1);
|
||||
assert(r1[0].uri === '/route1');
|
||||
assert(r1[0].method === 'GET');
|
||||
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[0].uri === '/route2');
|
||||
assert(r2[0].method === 'POST');
|
||||
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[0].uri === '/route3');
|
||||
assert(r3[0].method === 'GET');
|
||||
assert(r3[0].middleware === middleware3);
|
||||
|
||||
r3 = router.routes('/route3', 'POST');
|
||||
r3 = router.routes(application, {uri: '/route3', method: 'POST'});
|
||||
assert(r3.length === 1);
|
||||
assert(r3[0].uri === '/route3');
|
||||
assert(r3[0].method === 'POST');
|
||||
assert(r3[0].middleware === middleware3);
|
||||
|
||||
r3 = router.routes('/route3', 'PUT');
|
||||
r3 = router.routes(application, {uri: '/route3', method: 'PUT'});
|
||||
assert(r3.length === 1);
|
||||
assert(r3[0].uri === '/route3');
|
||||
assert(r3[0].method === 'PUT');
|
||||
assert(r3[0].middleware === middleware3);
|
||||
|
||||
r3 = router.routes('/route3', 'DELETE');
|
||||
r3 = router.routes(application, {uri: '/route3', method: 'DELETE'});
|
||||
assert(r3.length === 1);
|
||||
assert(r3[0].uri === '/route3');
|
||||
assert(r3[0].method === 'DELETE');
|
||||
@ -107,7 +111,7 @@ describe('Router', () => {
|
||||
|
||||
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[0].uri instanceof RegExp);
|
||||
assert(r[0].uri.toString() === new RegExp('^\/route1').toString());
|
||||
@ -120,7 +124,7 @@ describe('Router', () => {
|
||||
|
||||
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[0].uri === '/route1/subroute');
|
||||
});
|
||||
@ -130,7 +134,7 @@ describe('Router', () => {
|
||||
|
||||
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[0].uri === '/route1');
|
||||
});
|
||||
@ -140,7 +144,7 @@ describe('Router', () => {
|
||||
|
||||
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[0].uri === '/route1/subroute');
|
||||
});
|
||||
@ -150,7 +154,7 @@ describe('Router', () => {
|
||||
|
||||
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[0].uri === '/route1/subroute');
|
||||
|
||||
@ -160,7 +164,7 @@ describe('Router', () => {
|
||||
|
||||
router.get(new frontexpress.Middleware());
|
||||
|
||||
r = router.routes('/route1', 'GET');
|
||||
r = router.routes(application, {uri: '/route1', method: 'GET'});
|
||||
assert(r.length === 1);
|
||||
assert(r[0].uri === '/route1');
|
||||
});
|
||||
@ -170,7 +174,7 @@ describe('Router', () => {
|
||||
|
||||
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[0].uri === '/route1/subroute');
|
||||
assert(r[0].data === undefined);
|
||||
@ -181,7 +185,7 @@ describe('Router', () => {
|
||||
|
||||
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[0].uri === '/route1/subroute');
|
||||
assert(r[0].data === undefined);
|
||||
@ -192,7 +196,7 @@ describe('Router', () => {
|
||||
|
||||
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[0].uri === '/route1/subroute');
|
||||
assert(r[0].data === undefined);
|
||||
@ -264,7 +268,7 @@ describe('Router', () => {
|
||||
|
||||
router.get(middleware);
|
||||
|
||||
const r = router.routes('/', 'GET');
|
||||
const r = router.routes(application, {uri: '/', method: 'GET'});
|
||||
assert(r.length === 1);
|
||||
assert(r[0].uri === '/');
|
||||
assert(r[0].method === 'GET');
|
||||
@ -277,7 +281,7 @@ describe('Router', () => {
|
||||
|
||||
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[0].uri === '/route1');
|
||||
assert(r[0].method === 'GET');
|
||||
@ -295,7 +299,7 @@ describe('Router', () => {
|
||||
const middleware = new frontexpress.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[0].uri instanceof RegExp);
|
||||
assert(r[0].uri.toString() === new RegExp('^\/part').toString());
|
||||
@ -303,4 +307,113 @@ describe('Router', () => {
|
||||
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*/
|
||||
import {assert} from 'chai';
|
||||
import chai, {assert} from 'chai';
|
||||
import Settings from '../lib/settings';
|
||||
|
||||
describe('Settings', () => {
|
||||
const settings = new Settings();
|
||||
|
||||
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', () => {
|
||||
const uriFn = settings.get('http GET transformer').uri;
|
||||
const dataFn = settings.get('http GET transformer').data;
|
||||
|
Loading…
Reference in New Issue
Block a user