route-trie
Advanced tools
Comparing version 0.2.1 to 1.0.0
@@ -7,3 +7,3 @@ { | ||
], | ||
"version": "0.2.1", | ||
"version": "1.0.0", | ||
"main": "index.js", | ||
@@ -10,0 +10,0 @@ "repository": { |
@@ -7,3 +7,3 @@ { | ||
], | ||
"version": "0.2.1", | ||
"version": "1.0.0", | ||
"main": "index.js", | ||
@@ -10,0 +10,0 @@ "repository": { |
82
index.js
@@ -28,3 +28,5 @@ // **Github:** https://github.com/zensh/route-trie | ||
Trie.prototype.define = function(pattern) { | ||
if (typeof pattern !== 'string') throw new TypeError('Only strings can be defined.'); | ||
if (typeof pattern !== 'string') | ||
throw new TypeError('Only strings can be defined.'); | ||
var _pattern = pattern | ||
@@ -37,6 +39,7 @@ .replace(multiSlashReg, '\/') | ||
if (node._nodeState.pattern == null) node._nodeState.pattern = pattern; | ||
return node; | ||
}; | ||
Trie.prototype.match = function(path) { | ||
Trie.prototype.match = function(path, multiMatch) { | ||
// the path should be normalized before match, just as path.normalize do in Node.js | ||
@@ -46,37 +49,22 @@ path = path | ||
.replace(trimSlashReg, ''); | ||
var frag = ''; | ||
var node = this.root; | ||
var frags = path.split('/'); | ||
var result = { | ||
params: {}, | ||
node: null | ||
}; | ||
var node = this.root; | ||
var child = null; | ||
var frag = ''; | ||
var result = {params: {}}; | ||
if (multiMatch) result.nodes = []; | ||
while (frags.length) { | ||
frag = safeDecodeURIComponent(frags.shift()); | ||
if (frag === false) return null; | ||
child = node._nodeState.childNodes[this.flags ? frag.toLowerCase() : frag]; | ||
if (!child) { | ||
for (var i = 0, len = node._nodeState.regexChildNodes.length; i < len; i++) { | ||
var regex = node._nodeState.regexChildNodes[i]; | ||
if (regex[2] && !regex[2].test(frag)) continue; | ||
if (regex[0]._nodeState.matchRemaining) { | ||
while (frags.length) { | ||
var _frag = safeDecodeURIComponent(frags.shift()); | ||
if (_frag === false) return null; | ||
frag += '/' + _frag; | ||
} | ||
} | ||
if (regex[1]) result.params[regex[1]] = frag; | ||
child = regex[0]; | ||
break; | ||
} | ||
node = matchNode(node, frags, result.params, this.flags); | ||
if (node) { | ||
if (multiMatch && node._nodeState.endpoint) result.nodes.push(node); | ||
continue; | ||
} | ||
if (!child) return null; | ||
node = child; | ||
if (!multiMatch) return null; | ||
break; | ||
} | ||
if (multiMatch) return result; | ||
if (!node._nodeState.endpoint) return null; | ||
result.node = node; | ||
@@ -115,2 +103,28 @@ return result; | ||
function matchNode(node, frags, params, flags) { | ||
var frag = safeDecodeURIComponent(frags.shift()); | ||
if (frag === false) return null; | ||
var nodeState = node._nodeState; | ||
var child = nodeState.childNodes[flags ? frag.toLowerCase() : frag]; | ||
if (child) return child; | ||
for (var i = 0, len = nodeState.regexChildNodes.length; i < len; i++) { | ||
var regex = nodeState.regexChildNodes[i]; | ||
if (regex[2] && !regex[2].test(frag)) continue; | ||
if (regex[0]._nodeState.matchRemaining) { | ||
while (frags.length) { | ||
var _frag = safeDecodeURIComponent(frags.shift()); | ||
if (_frag === false) return null; | ||
frag += '/' + _frag; | ||
} | ||
} | ||
if (regex[1]) params[regex[1]] = frag; | ||
child = regex[0]; | ||
break; | ||
} | ||
return child; | ||
} | ||
function parseNode(parentNode, frag, flags) { | ||
@@ -146,5 +160,5 @@ var node = null; | ||
if (regexNames[frag] >= 0) node = regexChildNodes[regexNames[frag]][0]; | ||
else if (lastRegexChildNode && lastRegexChildNode._nodeState.matchRemaining) { | ||
else if (lastRegexChildNode && lastRegexChildNode._nodeState.matchRemaining) | ||
throw new Error('Can not define more regex pattern while "*" pattern defined'); | ||
} else { | ||
else { | ||
node = new Node(frag, matchRemaining); | ||
@@ -176,4 +190,4 @@ regexChildNodes.push([node, parameter, frag && new RegExp(frag, flags)]); | ||
Trie.NAME = 'Trie'; | ||
Trie.VERSION = 'v0.2.1'; | ||
Trie.VERSION = 'v1.0.0'; | ||
return Trie; | ||
})); |
@@ -7,3 +7,3 @@ { | ||
], | ||
"version": "0.2.1", | ||
"version": "1.0.0", | ||
"main": "index.js", | ||
@@ -10,0 +10,0 @@ "repository": { |
@@ -8,3 +8,3 @@ route-trie | ||
### [trie](http://en.wikipedia.org/wiki/Trie) | ||
### About [trie](http://en.wikipedia.org/wiki/Trie) | ||
@@ -39,7 +39,11 @@ ### [Trie-based request routing](http://blog.vulcanproxy.com/trie-based-http-requests-routing/) | ||
npm install route-trie | ||
```sh | ||
npm install route-trie | ||
``` | ||
**Bower:** | ||
bower install route-trie | ||
```sh | ||
bower install route-trie | ||
``` | ||
@@ -54,10 +58,11 @@ ## API | ||
`flagI`: `Boolean`, default `false`, ignore case. | ||
Create a trie. | ||
```js | ||
var trie = new Trie(); | ||
``` | ||
- `flagI`: {Boolean}, default `false`, ignore case | ||
return `trie` object. | ||
```js | ||
var trie = new Trie(true); // ignore case for match | ||
var trie1 = new Trie(); | ||
var trie2 = new Trie(true); // ignore case for match | ||
``` | ||
@@ -67,2 +72,16 @@ | ||
Define a `node` for the `pattern`, The same pattern will always return the same `node`. The result `node`, will be an emtpy object, it has a private and not enumerable property `_nodeState`. `_nodeState` is a object that have `name`, `pattern`, `childNodes` and so on. You can mount properties and methods on the `node`, but not on `_nodeState`. | ||
- `pattern`: {String}, each fragment of the pattern, delimited by a `/`, can have the following signature: | ||
- `string` - ex `/post` | ||
- `string|string` - `|` separated strings, ex `/post|task` | ||
- `:name` - Wildcard route matched to a name, ex `/:type` | ||
- `(regex)` - A regular expression match without saving the parameter (not recommended), ex `/(post|task)`, `/([a-z0-9]{6})` | ||
- `:name(regex)`- Named regular expression match ex `/:type/:id([a-z0-9]{6})` | ||
- `*` - Match remaining path without saving the parameter (not recommended), ex `/*` will match all path. | ||
- `:name(*)`- Named regular expression match, match remaining path, ex `/:type/:other(*)` will match `/post/x` or `/task/x/y` or `/any/x/y/z`... | ||
return a `node` object. | ||
```js | ||
@@ -77,30 +96,30 @@ var node = trie.define('/:type/:id([a-z0-9]{6})'); | ||
The result `node`, will be an emtpy object, it has a private and not enumerable property `_nodeState`. | ||
### Trie.prototype.match(path[, multiMatch]) | ||
Each fragment of the pattern, delimited by a `/`, can have the following signature: | ||
- `path`: {String}, URL pathname to match and get the defined `node` | ||
- `multiMatch`: {Boolean}, *Optional*, default: `false`. If true, a path maybe matched one more `node`s. | ||
- `string` - ex `/post` | ||
- `string|string` - `|` separated strings, ex `/post|task` | ||
- `:name` - Wildcard route matched to a name, ex `/:type` | ||
- `(regex)` - A regular expression match without saving the parameter (not recommended), ex `/(post|task)`, `/([a-z0-9]{6})` | ||
- `:name(regex)`- Named regular expression match ex `/:type/:id([a-z0-9]{6})` | ||
- `*` - Match remaining path without saving the parameter (not recommended), ex `/*` will match all path. | ||
- `:name(*)`- Named regular expression match, match remaining path, ex `/:type/:other(*)` will match `/post/x` or `/task/x/y` or `/any/x/y/z`... | ||
Return `matched` object: | ||
### Trie.prototype.match(path) | ||
- **Default mode**: return `null` if no node matched, otherwise return an object with the following properties: | ||
```js | ||
var match = trie.match('/post'); | ||
// assert(match === null); | ||
- `params`: {Object}, A list of named parameters, ex, `match.params.id === 'abc123'`. | ||
- `node`: {Object}, The matched node. | ||
match = trie.match('/post/abc123'); | ||
// assert(match.node === trie.define('/:type/:id([a-z0-9]{6}')); | ||
// assert.deepEqual(match.params, {type: 'post', id: 'abc123'}) | ||
``` | ||
```js | ||
var node = trie.define('/:type/:id([a-z0-9]{6}'); | ||
var match = trie.match('/post'); | ||
// assert(match === null); | ||
The result `match`, unless `null`, will be an object with the following properties: | ||
match = trie.match('/post/abc123'); | ||
// assert(match.node === node); | ||
// assert.deepEqual(match.params, {type: 'post', id: 'abc123'}) | ||
``` | ||
- `params` - A list of named parameters, ex, `match.params.id === 'abc123'`. | ||
- `node` - The matched node. | ||
- **multiMatch mode**: will always return an object with the following properties: | ||
- `params`: {Object}, A list of named parameters. | ||
- `nodes`: {Array}, if no node matched, it will be a empty array, otherwise will be a array of matched nodes. | ||
[npm-url]: https://npmjs.org/package/route-trie | ||
@@ -107,0 +126,0 @@ [npm-image]: http://img.shields.io/npm/v/route-trie.svg |
@@ -252,2 +252,40 @@ 'use strict'; | ||
}); | ||
it('trie.match, multiMatch', function() { | ||
var trie = new Trie(); | ||
var node1 = trie.define('/'); | ||
var node2 = trie.define('/:type'); | ||
var node3 = trie.define('/:type/:id([a-z0-9]{6}'); | ||
var match = trie.match('/', true); | ||
assert.strictEqual(match.nodes.length, 1); | ||
assert.strictEqual(match.nodes[0], node1); | ||
assert.deepEqual(match.params, {}); | ||
// should not match node1(root node)! | ||
match = trie.match('/post', true); | ||
assert.strictEqual(match.nodes.length, 1); | ||
assert.strictEqual(match.nodes[0], node2); | ||
assert.deepEqual(match.params, {type: 'post'}); | ||
match = trie.match('/post/abcdef', true); | ||
assert.strictEqual(match.nodes.length, 2); | ||
assert.strictEqual(match.nodes[0], node2); | ||
assert.strictEqual(match.nodes[1], node3); | ||
assert.deepEqual(match.params, {type: 'post', id: 'abcdef'}); | ||
match = trie.match('/post/abcdef/xyz', true); | ||
assert.strictEqual(match.nodes.length, 2); | ||
assert.strictEqual(match.nodes[0], node2); | ||
assert.strictEqual(match.nodes[1], node3); | ||
assert.deepEqual(match.params, {type: 'post', id: 'abcdef'}); | ||
match = trie.match('/post/abcdef/xyz/123', true); | ||
assert.strictEqual(match.nodes.length, 2); | ||
assert.strictEqual(match.nodes[0], node2); | ||
assert.strictEqual(match.nodes[1], node3); | ||
assert.deepEqual(match.params, {type: 'post', id: 'abcdef'}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
23859
495
0
125