radix-router
Advanced tools
Comparing version 0.1.3 to 0.1.4
188
index.js
@@ -11,3 +11,3 @@ 'use strict'; | ||
// no-op | ||
// noop | ||
function noop() {} | ||
@@ -99,26 +99,29 @@ | ||
var wildcardNode = null; | ||
for (var i = 0; i < children.length; i++) { | ||
childNode = children[i]; | ||
if (children[i].type === WILDCARD_NODE) { | ||
wildcardNode = childNode; | ||
break; | ||
} else if (children[i].type === PLACEHOLDER_NODE) { | ||
var key = childNode.path.slice(1); | ||
var slashIndex = str.indexOf('/'); | ||
var param; | ||
if (slashIndex !== -1) { | ||
param = str.slice(0, slashIndex); | ||
} else { | ||
param = str; | ||
} | ||
options.node = children[i]; | ||
options.str = str.slice(param.length); | ||
if (onPlaceholder) { | ||
for (var i = 0; i < children.length; i++) { | ||
childNode = children[i]; | ||
if (children[i].type === WILDCARD_NODE) { | ||
wildcardNode = childNode; | ||
} else if (children[i].type === PLACEHOLDER_NODE) { | ||
var key = childNode.path.slice(1); | ||
var slashIndex = str.indexOf('/'); | ||
onPlaceholder(key, param, data); | ||
// return the child node if there is nowhere else to go | ||
// otherwise, traverse to the child | ||
if (options.str.length === 0) { | ||
return children[i]; | ||
var param; | ||
if (slashIndex !== -1) { | ||
param = str.slice(0, slashIndex); | ||
} else { | ||
param = str; | ||
} | ||
options.node = children[i]; | ||
options.str = str.slice(param.length); | ||
return onPlaceholder({ | ||
key: key, | ||
param: param, | ||
data: data, | ||
options: options, | ||
childNode: childNode | ||
}); | ||
} | ||
return _traverse(options); | ||
} | ||
@@ -131,3 +134,3 @@ } | ||
if (prefix.length === 0) { | ||
return onNoMatch(node, str, data) || wildcardNode; | ||
return onNoMatch(options) || wildcardNode; | ||
} | ||
@@ -137,3 +140,8 @@ | ||
if (prefix.length === str.length) { | ||
return onExactMatch(node, prefix, str, data) || wildcardNode; | ||
return onExactMatch({ | ||
node: node, | ||
prefix: prefix, | ||
str: str, | ||
data: data | ||
}) || wildcardNode; | ||
} | ||
@@ -147,3 +155,3 @@ | ||
options.str = str.slice(prefix.length); | ||
let result = _traverse(options); | ||
var result = _traverse(options); | ||
// if no result, return the wildcard node | ||
@@ -158,3 +166,8 @@ if (!result && wildcardNode) { | ||
// partial match was found | ||
return onPartialMatch(node, prefix, str, data) || wildcardNode; | ||
return onPartialMatch({ | ||
node: node, | ||
prefix: prefix, | ||
str: str, | ||
data: data | ||
}) || wildcardNode; | ||
} | ||
@@ -169,9 +182,12 @@ | ||
*/ | ||
function _traverseDepths(node, str, map) { | ||
function _traverseDepths(node, str, array) { | ||
if (node.data) { | ||
map[str] = node.data; | ||
array.push({ | ||
path: str, | ||
data: node.data | ||
}); | ||
} | ||
node.children.forEach(function(child) { | ||
_traverseDepths(child, str + child.path, map); | ||
_traverseDepths(child, str + child.path, array); | ||
}); | ||
@@ -287,3 +303,7 @@ } | ||
var EXACT_MATCH_HANDLERS = { | ||
'insert': function(node, prefix, str, data) { | ||
'insert': function(options) { | ||
var node = options.node; | ||
var prefix = options.prefix; | ||
var str = options.str; | ||
var data = options.data; | ||
var childNode = _getChildNode(node, prefix); | ||
@@ -293,3 +313,5 @@ childNode.data = data; | ||
}, | ||
'delete': function(parentNode, prefix) { | ||
'delete': function(options) { | ||
var parentNode = options.node; | ||
var prefix = options.prefix; | ||
var childNode = _getChildNode(parentNode, prefix); | ||
@@ -305,11 +327,16 @@ if (childNode.children.length === 0) { | ||
} else { | ||
delete childNode.data; | ||
childNode.data = null; | ||
} | ||
return childNode; | ||
}, | ||
'lookup': function(node, prefix) { | ||
'lookup': function(options) { | ||
var node = options.node; | ||
var prefix = options.prefix; | ||
var discoveredNode = _getChildNode(node, prefix); | ||
return discoveredNode; | ||
}, | ||
'startsWith': function(node, prefix, str) { | ||
'startsWith': function(options) { | ||
var node = options.node; | ||
var prefix = options.prefix; | ||
var str = options.str; | ||
var childNode = _getChildNode(node, prefix); | ||
@@ -325,3 +352,7 @@ if (childNode) { | ||
var PARTIAL_MATCH_HANDLERS = { | ||
'insert': function(node, prefix, str, data) { | ||
'insert': function(options) { | ||
var node = options.node; | ||
var prefix = options.prefix; | ||
var str = options.str; | ||
var data = options.data; | ||
var newNode = _splitNode(node, prefix, str, data); | ||
@@ -333,6 +364,8 @@ return newNode; | ||
}, | ||
'lookup': function(node) { | ||
'lookup': function() { | ||
return null; | ||
}, | ||
'startsWith': function(node, prefix) { | ||
'startsWith': function(options) { | ||
var node = options.node; | ||
var prefix = options.prefix; | ||
return _getAllPrefixChildren(node, prefix); | ||
@@ -344,3 +377,7 @@ } | ||
var NO_MATCH_HANDLERS = { | ||
'insert': function(parentNode, str, data) { | ||
'insert': function(options) { | ||
var parentNode = options.node; | ||
var prefix = options.prefix; | ||
var str = options.str; | ||
var data = options.data; | ||
var newNode = _buildNodeChain(str, data); | ||
@@ -362,5 +399,31 @@ parentNode.children.push(newNode); | ||
function _onPlaceholder(placeholderOptions) { | ||
var options = placeholderOptions.options; | ||
var childNode = options.node; | ||
var parentNode = options.node.parent; | ||
var str = options.str; | ||
var data = options.data; | ||
// return the child node if there is nowhere else to go | ||
// otherwise, traverse to the child | ||
if (options.str.length === 0) { | ||
return options.onExactMatch({ | ||
node: parentNode, | ||
prefix: childNode.path, | ||
str: str, | ||
data: data | ||
}); | ||
} | ||
return _traverse(options); | ||
} | ||
// handle situations where a place holder was found | ||
var PLACEHOLDER_HANDLERS = { | ||
'lookup': function(key, param, data) { | ||
// lookup handles placeholders differently | ||
'lookup': function(placeholderOptions) { | ||
var key = placeholderOptions.key; | ||
var param = placeholderOptions.param; | ||
var options = placeholderOptions.options; | ||
var data = options.data; | ||
if (!data.params) { | ||
@@ -370,7 +433,13 @@ data.params = {}; | ||
data.params[key] = param; | ||
if (options.str.length === 0) { | ||
return options.node; | ||
} | ||
return _traverse(options); | ||
}, | ||
// no ops, (maybe add different functionality later?) | ||
'delete': noop, | ||
'insert': noop, | ||
'startsWith': noop | ||
// inserts shouldn't care about placeholders at all | ||
'insert': null, | ||
'delete': _onPlaceholder, | ||
'startsWith': _onPlaceholder | ||
}; | ||
@@ -393,6 +462,12 @@ | ||
function _validateInput(str) { | ||
if (typeof str !== 'string') { | ||
function _validateInput(input) { | ||
var path = input; | ||
if (typeof path !== 'string') { | ||
throw new Error('Radix Tree input must be a string'); | ||
} | ||
// allow for trailing slashes to match by removing it | ||
if (path[path.length -1] === '/') { | ||
path = path.slice(0, path.length -1); | ||
} | ||
return path; | ||
} | ||
@@ -445,7 +520,8 @@ | ||
lookup: function(input) { | ||
_validateInput(input); | ||
var path = _validateInput(input); | ||
var result = { | ||
path: input, | ||
data: null | ||
}; | ||
var node = _startTraversal(this._rootNode, 'lookup', input, result); | ||
var node = _startTraversal(this._rootNode, 'lookup', path, result); | ||
result.data = node ? node.data : null; | ||
@@ -459,5 +535,5 @@ return result; | ||
var map = {}; | ||
var resultArray = []; | ||
if (result instanceof Node) { | ||
_traverseDepths(result, prefix, map); | ||
_traverseDepths(result, prefix, resultArray); | ||
} else { | ||
@@ -467,16 +543,16 @@ result.forEach(function(child) { | ||
prefix.substring(0, prefix.indexOf(child.path[0])) + child.path, | ||
map); | ||
resultArray); | ||
}); | ||
} | ||
return map; | ||
return resultArray; | ||
}, | ||
insert: function(input, data) { | ||
_validateInput(input); | ||
return _startTraversal(this._rootNode, 'insert', input, data); | ||
var path = _validateInput(input); | ||
return _startTraversal(this._rootNode, 'insert', path, data); | ||
}, | ||
delete: function(input) { | ||
_validateInput(input); | ||
return _startTraversal(this._rootNode, 'delete', input); | ||
var path = _validateInput(input); | ||
return _startTraversal(this._rootNode, 'delete', path); | ||
} | ||
@@ -483,0 +559,0 @@ }; |
@@ -13,3 +13,3 @@ { | ||
"name": "radix-router", | ||
"version": "0.1.3", | ||
"version": "0.1.4", | ||
"description": "Radix tree based router", | ||
@@ -22,3 +22,6 @@ "main": "index.js", | ||
"author": "Charlie Duong <charlieduong94@gmail.com>", | ||
"license": "MIT" | ||
"license": "MIT", | ||
"scripts": { | ||
"test": "./run-tests.sh" | ||
} | ||
} |
# Radix Router | ||
[![Build Status](https://travis-ci.org/charlieduong94/radix-router.svg?branch=master)](https://travis-ci.org/charlieduong94/radix-router) | ||
A simple router implemented using a [Radix Tree](https://en.wikipedia.com/wiki/Radix_tree) (aka compact [Prefix Tree](https://en.wikipedia.com/wiki/Trie)). | ||
A router implemented using a [Radix Tree](https://en.wikipedia.com/wiki/Radix_tree) (aka compact [Prefix Tree](https://en.wikipedia.com/wiki/Trie)). | ||
This router has support for placeholders and wildcards. | ||
@@ -40,3 +42,3 @@ ### Installation | ||
router.insert('/api/v1/otherroute/:id', { | ||
router.insert('/api/v1/other-route/:id', { | ||
so: 'placeholder', | ||
@@ -47,28 +49,28 @@ much: 'wow' | ||
router.lookup('/api/v1/route'); | ||
returns { | ||
path: '/api/v1/route', | ||
data: { | ||
much: 'data' | ||
} | ||
} | ||
// returns { | ||
// path: '/api/v1/route', | ||
// data: { | ||
// much: 'data' | ||
// } | ||
// } | ||
router.lookup('/api/v2/anything/goes/here'); | ||
returns { | ||
path: '/api/v2/cool', | ||
data: { | ||
such: 'wildcard' | ||
} | ||
} | ||
// returns { | ||
// path: '/api/v2/cool', | ||
// data: { | ||
// such: 'wildcard' | ||
// } | ||
// } | ||
router.lookup('/api/v1/other-route/abcd'); | ||
returns { | ||
path: '/api/v1/other-route/abcd', | ||
data: { | ||
so: 'placeholder', | ||
much: 'wow' | ||
}, | ||
params: { | ||
id: 'abcd' | ||
} | ||
} | ||
// returns { | ||
// path: '/api/v1/other-route/abcd', | ||
// data: { | ||
// so: 'placeholder', | ||
// much: 'wow' | ||
// }, | ||
// params: { | ||
// id: 'abcd' | ||
// } | ||
// } | ||
@@ -79,17 +81,17 @@ // remove route | ||
router.lookup('/api/v2/anything/goes/here'); | ||
returns { | ||
path: '/api/v2/cool', | ||
data: null | ||
} | ||
// returns { | ||
// path: '/api/v2/cool', | ||
// data: null | ||
// } | ||
route.startsWith('/api') | ||
returns { | ||
'/api/v1/route': { | ||
much: 'data' | ||
}, | ||
'/api/v1/other-route/:id': { | ||
so: 'placeholder', | ||
much: 'wow' | ||
} | ||
} | ||
// returns { | ||
// '/api/v1/route': { | ||
// much: 'data' | ||
// }, | ||
// '/api/v1/other-route/:id': { | ||
// so: 'placeholder', | ||
// much: 'wow' | ||
// } | ||
// } | ||
``` |
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
55058
18
724
95