<commit_before># controller-router
## URL -> controller router

Basic example of router configuration:

```javascript
var getRouter = require('controler-router');

// Provide a routes and get router:
var router = getRouter({
  // '/' route
  '/': function () {
    console.log("Root!");
  },
  // '/foo' route
  'foo': function () {
    console.log("Foo!");
  },
  // '/foo/bar' route
  'foo/bar': function () {
    console.log("Foo, Bar!");
  },
  // '/lorem/*' dynamic route
  'lorem/[0-9][0-9a-z]+': {
    match: function (id) {
      if (id !== '0abc') return false;
        // for demo purposes, pass only '0abc'
        this.name = id;
      },
    controller: function () {
      console.log("Lorem, " + this.name + "!");
    }
  }
});

router('/'); // Calls "/" controller (logs "Root!") and returns route call event object
router('/foo/'); // "Foo!"
router('/not-existing/'); // Not found, returns false
router('/foo/bar/'); // "Foo, Bar!"
router('/lorem/elo'); // Not found, returns false
router('/lorem/0abc'); // "Lorem, 0abc!"
```

### Installation

	$ npm install controller-router

### API

#### getRouter(routes)

```javascript
var getRouter = require('controller-router');

var router = getRouter({
  // .. routes configuration
});

router('/foo/bar'); // invoke controller for '/foo/bar' path
```

Main module exports `getRouter(routes)` function, which accepts routes configuration (typical hash map), and returns `router` function.

##### Routes configuration

In routes map, _key_ is a path, and _value_ is a controller. Routes are defined as flat map, there are no nested route configurations.

###### Path keys

A valid path key is a series of tokens separated with `/` character. Where a token for typical static path is built strictly out of `a-z, 0-9, -` characters set.

We can also mix into path a dynamic path tokens, which we describe in regular expression format, but it is assumed that all tokens also resolve strictly to values built out of  `a-z, 0-9, -` character set.

Internally engine naturally distinguish between static and dynamic tokens on basis of fact that regular expression will use characters out of basic set.

In addition to above, a `/` key is understood as root url.

Examples of static path keys:
- __/__ - root url, matches strictly `/` route
- __foo__ - matches `/foo` or `/foo/` route
- __foo/bar/elo__ - matches `/foo/bar/elo` or `/foo/bar/elo/` route

Examples of dynamic path keys:
- __[a-z]{3}__ - matches e.g. `/abc` `/zws/` `/aaa/`, won't match e.g. `/ab0` or `/abcd`
- __user/[0-9][a-z0-9]{6}__ - matches e.g. `/user/0asd34d` or `/user/7few232` route
- __lorem/[0-9][a-z0-9]{6}/foo/[a-z]{1,2}__ - matches e.g. `/lorem/0asd34d/foo.` or `/user/7few232` route

Routes for dynamic path keys, can be combined with static that override them. e.g. we may have configuration for _user/[a-z]{3,10}_ and _user/mark_, and `/user/mark` url will be routed to __user/mark__ configuration, as it has higher specifity for given path

###### Controller values

For static path keys, controllers may be direct functions e.g.:
```javascript
'foo/bar': function () {
  // controller body
}
```

They can also be configured with objects which provide a `controller` property:
```javascript
'foo/bar': {
  controller: function () {
    // controller body
  }
};
```

Two of above configurations are equal in meaning.

If path key contains dynamic tokens, then `match` function is required, and configuration must be configured as:

```javascript
'lorem/[0-9][a-z0-9]{6}/foo/[a-z]{1,2}': {
  match: function (token1, token2) {
    if (!loremExists(token1) || !fooExists(token2)) {
      // while tokens matched pattern, no corresponding entities were found
      return false;
    }
    this.lorem = resolveLorem(token1);
    this.foo = resolve(token2);
    return true;
  },
  controller: function () {
    // controller body
    doSomethingWith(this.lorem, this.foo);
  }
};
```

###### Handling of `router` function

`router.call(routeEvent, path, ...controllerArguments)`

Router function maybe invoked just with `path` argument as `router(path)`, but it can also be used to pass preprepared `routeEvent` or to pass some arguments to controllers.

`routeEvent`, so context in which `router` function is invoked, will be used as a context for controller invocation. If `router` was called without a context, then internally created empty plain object is used for a `routeEvent`.

`routeEvent` should be unique per each route call and it should be used as a transport for values that we resolve at _match_ step, and want to access at _controller_ step (both `match` and `controller` are run in this context).

If we want to pass some values as arguments to controller they can be passed to `router` after _path_ argument. They won't however be provided to `match` function, as all it receives is tokens as resolved from url.

###### Router return values

`router.call(routeEvent, path, ...controllerArgs)` function when invoked returns either `false` when no controller for given path was found, or in case of valid route a result object which has two properties:
- `conf` a route configuration for chosen path (as it's provided on routes object)
- `result` a result value as returned by invoked controller

#### nestRoutes(path, routes[, match])

```javascript
var nestRoutes = require('controller-router/nest');

var routes = {
  bar: function barController() { ... }
};

var nestedAgainstFoo = nestRoutes('foo', routes);
console.log(nestedAgainstFoo);
// { 'foo/bar': fuction barController() { ... } }<commit_msg>Documentation<commit_after># controller-router
## URL -> controller router

Basic example of router configuration:

```javascript
var getRouter = require('controler-router');

// Provide a routes and get router:
var router = getRouter({
  // '/' route
  '/': function () {
    console.log("Root!");
  },
  // '/foo' route
  'foo': function () {
    console.log("Foo!");
  },
  // '/foo/bar' route
  'foo/bar': function () {
    console.log("Foo, Bar!");
  },
  // '/lorem/*' dynamic route
  'lorem/[0-9][0-9a-z]+': {
    match: function (id) {
      if (id !== '0abc') return false;
        // for demo purposes, pass only '0abc'
        this.name = id;
      },
    controller: function () {
      console.log("Lorem, " + this.name + "!");
    }
  }
});

router('/'); // Calls "/" controller (logs "Root!") and returns route call event object
router('/foo/'); // "Foo!"
router('/not-existing/'); // Not found, returns false
router('/foo/bar/'); // "Foo, Bar!"
router('/lorem/elo'); // Not found, returns false
router('/lorem/0abc'); // "Lorem, 0abc!"
```

### Installation

	$ npm install controller-router

### API

#### getRouter(routes[, options])

```javascript
var getRouter = require('controller-router');

var router = getRouter({
  // .. routes configuration
});

router('/foo/bar'); // invoke controller for '/foo/bar' path
```

Main module exports `getRouter(routes)` function, which accepts routes configuration (typical hash map), and returns `router` function.

Supported options:
- __eventProto__ - Prototype for route events. If provided, then each `routeEvent` will be an instance that inherits from this object.
For more information about `routeEvent`, see [Handling of router function](https://github.com/medikoo/controller-router#handling-of-router-function) section.

##### Routes configuration

In routes map, _key_ is a path, and _value_ is a controller. Routes are defined as flat map, there are no nested route configurations.

###### Path keys

A valid path key is a series of tokens separated with `/` character. Where a token for typical static path is built strictly out of `a-z, 0-9, -` characters set.

We can also mix into path a dynamic path tokens, which we describe in regular expression format, but it is assumed that all tokens also resolve strictly to values built out of  `a-z, 0-9, -` character set.

Internally engine naturally distinguish between static and dynamic tokens on basis of fact that regular expression will use characters out of basic set.

In addition to above, a `/` key is understood as root url.

Examples of static path keys:
- __/__ - root url, matches strictly `/` route
- __foo__ - matches `/foo` or `/foo/` route
- __foo/bar/elo__ - matches `/foo/bar/elo` or `/foo/bar/elo/` route

Examples of dynamic path keys:
- __[a-z]{3}__ - matches e.g. `/abc` `/zws/` `/aaa/`, won't match e.g. `/ab0` or `/abcd`
- __user/[0-9][a-z0-9]{6}__ - matches e.g. `/user/0asd34d` or `/user/7few232` route
- __lorem/[0-9][a-z0-9]{6}/foo/[a-z]{1,2}__ - matches e.g. `/lorem/0asd34d/foo.` or `/user/7few232` route

Routes for dynamic path keys, can be combined with static that override them. e.g. we may have configuration for _user/[a-z]{3,10}_ and _user/mark_, and `/user/mark` url will be routed to __user/mark__ configuration, as it has higher specifity for given path

###### Controller values

For static path keys, controllers may be direct functions e.g.:
```javascript
'foo/bar': function () {
  // controller body
}
```

They can also be configured with objects which provide a `controller` property:
```javascript
'foo/bar': {
  controller: function () {
    // controller body
  }
};
```

Two of above configurations are equal in meaning.

If path key contains dynamic tokens, then `match` function is required, and configuration must be configured as:

```javascript
'lorem/[0-9][a-z0-9]{6}/foo/[a-z]{1,2}': {
  match: function (token1, token2) {
    if (!loremExists(token1) || !fooExists(token2)) {
      // while tokens matched pattern, no corresponding entities were found
      return false;
    }
    this.lorem = resolveLorem(token1);
    this.foo = resolve(token2);
    return true;
  },
  controller: function () {
    // controller body
    doSomethingWith(this.lorem, this.foo);
  }
};
```

###### Handling of `router` function

`router(path[, ...controllerArguments])`

Router function when invoked with `path` argument, resolves controller for given path, and if one is found, it is invoked.  
Additionally, when calling `router`, after a path argument, we can pass arguments for _controller_ function (mind that those arguments won't be provided to eventual _match_ function)

For each `router` call, a new `routeEvent` is created (as a plain object, or as an extension to provided at initialization `eventProto` object).
It is used as a context for _match_ and _controller_ invocations, `routeEvent` should be used as a transport for values that we resolve at _match_ step, and want to access at _controller_ step.

If we call `route` function in a some context, then given context becomes a `routeEvent` object. That way we can override internal creation of `routeEvent` with object constructed externally.

```javascript
// overridenRouteEvent becomes context for eventual match and controller invocations
router.call(overridenRouteEvent, path, ...controllerArguments);
```

###### Router return values

`router.call(routeEvent, path, ...controllerArgs)` function when invoked returns either `false` when no controller for given path was found, or in case of valid route a result object which has two properties:
- `conf` a route configuration for chosen path (as it's provided on routes object)
- `result` a result value as returned by invoked controller

#### nestRoutes(path, routes[, match])

```javascript
var nestRoutes = require('controller-router/nest');

var routes = {
  bar: function barController() { ... }
};

var nestedAgainstFoo = nestRoutes('foo', routes);
console.log(nestedAgainstFoo);
// { 'foo/bar': fuction barController() { ... } }
{'fraction_non_alphanumeric': 0.1339146952167156, 'fraction_numerical': 0.009670177862199966, 'mean_word_length': 3.796273291925466, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2288308', 'n_tokens_mistral': 3496, 'n_tokens_neox': 3374, 'n_words': 1355}