Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

radix-router

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

radix-router - npm Package Compare versions

Comparing version 0.1.6 to 1.0.0

.eslintrc.yml

896

index.js

@@ -1,30 +0,28 @@

'use strict';
'use strict'
/**
* JS Radix Router implementation
*/
var assert = require('assert')
// node types
var NORMAL_NODE = 0;
var WILDCARD_NODE = 1;
var PLACEHOLDER_NODE = 2;
var NORMAL_NODE = 0
var WILDCARD_NODE = 1
var PLACEHOLDER_NODE = 2
// noop
function noop() {}
/**
* Returns all children that match the prefix
*
* @param {Node} - the node to check children for
* @param {prefix} - the prefix to match
* @param { Node } - the node to check children for
* @param { prefix } - the prefix to match
*/
function _getAllPrefixChildren(node, str) {
var nodes = [];
var children = node.children;
for (var i = 0; i < children.length; i++) {
// only need to check for first char
if (children[i].path[0] === str[0]) {
nodes.push(children[i]);
}
function _getAllPrefixChildren (node, str) {
var nodes = []
var children = node.children
for (var i = 0; i < children.length; i++) {
// only need to check for first char
if (children[i].path[0] === str[0]) {
nodes.push(children[i])
}
return nodes;
}
return nodes
}

@@ -35,13 +33,13 @@

*
* @param {Node} - the node to check children for
* @param {prefix} - the prefix to match
* @param { Node } - the node to check children for
* @param { prefix } - the prefix to match
*/
function _getChildNode(node, prefix) {
var children = node.children;
for (var i = 0; i < children.length; i++) {
if (children[i].path === prefix) {
return children[i];
}
function _getChildNode (node, prefix) {
var children = node.children
for (var i = 0; i < children.length; i++) {
if (children[i].path === prefix) {
return children[i]
}
return null;
}
return null
}

@@ -52,22 +50,23 @@

*
* @param {object <string, Node>} children - a dictionary of childNodes
* @param {string} str - the string used to find the largest prefix with
* @param { object <string, Node> } children - a dictionary of childNodes
* @param { string } str - the string used to find the largest prefix with
*/
function _getLargestPrefix(children, str) {
var index = 0;
for (var i = 0; i < children.length; i++) {
var path = children[i].path;
var totalIterations = Math.min(str.length, path.length);
for (; index < totalIterations; index++) {
if (str[index] !== path[index]) {
break;
}
}
if (index > 0) {
break;
}
function _getLargestPrefix (children, str) {
var index = 0
for (var i = 0; i < children.length; i++) {
var path = children[i].path
var totalIterations = Math.min(str.length, path.length)
while (index < totalIterations) {
if (str[index] !== path[index]) {
break
}
index++
}
if (index > 0) {
break
}
}
// largest prefix
return str.slice(0, index);
return str.slice(0, index)
}

@@ -78,93 +77,93 @@

*
* @param {Node} node - the node to attempt to traverse
* @param {string} str - the string used as the basis for traversal
* @param {function} onExactMatch - the handler for exact matches
* @param {function} onPartialMatch - the handler for partial matches
* @param {function} onNoMatch - the handler for when no match is found
* @param { Node } node - the node to attempt to traverse
* @param { string } str - the string used as the basis for traversal
* @param { function } onExactMatch - the handler for exact matches
* @param { function } onPartialMatch - the handler for partial matches
* @param { function } onNoMatch - the handler for when no match is found
*/
function _traverse(options) {
var node = options.node;
var str = options.str;
var onExactMatch = options.onExactMatch;
var onPartialMatch = options.onPartialMatch;
var onNoMatch = options.onNoMatch;
var onPlaceholder = options.onPlaceholder;
var data = options.data;
function _traverse (options) {
var node = options.node
var str = options.str
var onExactMatch = options.onExactMatch
var onPartialMatch = options.onPartialMatch
var onNoMatch = options.onNoMatch
var onPlaceholder = options.onPlaceholder
var data = options.data
var children = node.children;
var childNode;
var children = node.children
var childNode
// check if a child is possibly a placeholder or a wildcard
// if wildcard is found, use it as a backup if no result is found,
// if placeholder is found, grab the data and traverse
var wildcardNode = null;
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('/');
// check if a child is possibly a placeholder or a wildcard
// if wildcard is found, use it as a backup if no result is found,
// if placeholder is found, grab the data and traverse
var wildcardNode = null
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('/')
var param;
if (slashIndex !== -1) {
param = str.slice(0, slashIndex);
} else {
param = str;
}
var param
if (slashIndex !== -1) {
param = str.slice(0, slashIndex)
} else {
param = str
}
options.node = children[i];
options.str = str.slice(param.length);
options.node = children[i]
options.str = str.slice(param.length)
return onPlaceholder({
key: key,
param: param,
data: data,
options: options,
childNode: childNode
});
}
}
return onPlaceholder({
key: key,
param: param,
options: options,
childNode: childNode
})
}
}
}
var prefix = _getLargestPrefix(children, str);
var prefix = _getLargestPrefix(children, str)
// no matches, return null
if (prefix.length === 0) {
return onNoMatch(options) || wildcardNode;
}
// no matches, return null
if (prefix.length === 0) {
return onNoMatch(options) || wildcardNode
}
// exact match with input string was found
if (prefix.length === str.length) {
return onExactMatch({
node: node,
prefix: prefix,
str: str,
data: data
}) || wildcardNode;
}
// exact match with input string was found
if (prefix.length === str.length) {
return onExactMatch({
node: node,
prefix: prefix,
str: str,
data: data
}) || wildcardNode
}
// get child
childNode = _getChildNode(node, prefix);
// child exists, continue traversing
if (childNode) {
options.node = childNode;
options.str = str.slice(prefix.length);
var result = _traverse(options);
// if no result, return the wildcard node
if (!result && wildcardNode) {
return wildcardNode;
} else {
return result;
}
// get child
childNode = _getChildNode(node, prefix)
// child exists, continue traversing
if (childNode) {
options.node = childNode
options.str = str.slice(prefix.length)
var result = _traverse(options)
// if no result, return the wildcard node
if (!result && wildcardNode) {
return wildcardNode
} else {
return result
}
}
// partial match was found
return onPartialMatch({
node: node,
prefix: prefix,
str: str,
data: data
}) || wildcardNode;
// partial match was found
return onPartialMatch({
node: node,
prefix: prefix,
str: str,
data: data
}) || wildcardNode
}

@@ -175,17 +174,14 @@

*
* @param {Node} node - the node to attempt to traverse
* @param {string} str - the string that is the base of the key
* @param {object} map - the map to traverse the cobrowse event with
* @param { Node } node - the node to attempt to traverse
* @param { string } str - the string that is the base of the key
* @param { object } map - the map to traverse the cobrowse event with
*/
function _traverseDepths(node, str, array) {
if (node.data) {
array.push({
path: str,
data: node.data
});
}
function _traverseDepths (node, str, array) {
if (node.data) {
array.push(node.data)
}
node.children.forEach(function(child) {
_traverseDepths(child, str + child.path, array);
});
node.children.forEach(function (child) {
_traverseDepths(child, str + child.path, array)
})
}

@@ -196,72 +192,73 @@

*/
function _createNode(path, data) {
var node;
if (path[0] === ':') {
node = new Node(path, data, PLACEHOLDER_NODE);
} else if (path === '**') {
node = new Node(path, data, WILDCARD_NODE);
} else {
// normal string to match
node = new Node(path, data);
}
return node;
function _createNode (path, data) {
var node
if (path[0] === ':') {
node = new Node(path, data, PLACEHOLDER_NODE)
} else if (path === '**') {
node = new Node(path, data, WILDCARD_NODE)
} else {
// normal string to match
node = new Node(path, data)
}
return node
}
function _buildNodeChain(str, data) {
var parentNode;
var currentNode;
var startingPoint = 0;
function _buildNodeChain (str, data) {
var parentNode
var currentNode
var startingPoint = 0
// if the string is just a single slash, return the node
// otherwise just slash the node
if (str.length === 0 || str === '/') {
return new Node('/', data);
}
// if the string is just a single slash, return the node
// otherwise just slash the node
if (str.length === 0 || str === '/') {
return new Node('/', data)
}
var sections = str.split('/');
// first section is a special case, if it has real content, create a node
// otherwise, create an empty node
if (sections[startingPoint].length > 0) {
parentNode = currentNode = _createNode(sections[startingPoint]);
} else {
parentNode = currentNode = new Node('');
}
startingPoint++;
var sections = str.split('/')
for (var i = startingPoint; i < sections.length; i++) {
var parseRemaining = true;
var newNode;
// first section is a special case, if it has real content, create a node
// otherwise, create an empty node
if (sections[startingPoint].length > 0) {
parentNode = currentNode = _createNode(sections[startingPoint])
} else {
parentNode = currentNode = new Node('')
}
startingPoint++
// add slash to last node if the last section was empty
if (i > 0 && sections[i - 1].length === 0){
currentNode.path += '/';
} else if (sections[i].length === 0) {
newNode = new Node('/');
parseRemaining = false;
} else {
var node = new Node('/');
currentNode.children.push(node);
node.parent = currentNode;
currentNode = node;
}
for (var i = startingPoint; i < sections.length; i++) {
var parseRemaining = true
var newNode
if (parseRemaining) {
var path = sections[i];
newNode = _createNode(path);
}
currentNode.children.push(newNode);
newNode.parent = currentNode;
currentNode = newNode;
// add slash to last node if the last section was empty
if (i > 0 && sections[i - 1].length === 0) {
currentNode.path += '/'
} else if (sections[i].length === 0) {
newNode = new Node('/')
parseRemaining = false
} else {
var node = new Node('/')
currentNode.children.push(node)
node.parent = currentNode
currentNode = node
}
// if the last node's path is empty, remove it.
if (currentNode.path === '') {
currentNode.parent.children = [];
currentNode.parent.data = data;
} else {
currentNode.data = data;
if (parseRemaining) {
var path = sections[i]
newNode = _createNode(path)
}
return parentNode;
currentNode.children.push(newNode)
newNode.parent = currentNode
currentNode = newNode
}
// if the last node's path is empty, remove it.
if (currentNode.path === '') {
currentNode.parent.children = []
currentNode.parent.data = data
} else {
currentNode.data = data
}
return parentNode
}

@@ -273,40 +270,40 @@

*
* @param {Node} node - the node to split
* @param {string} prefix - the largest prefix found
* @param {string} str - the leftover parts of the input string
* @param {object} data - the data to store in the new node
* @param { Node } node - the node to split
* @param { string } prefix - the largest prefix found
* @param { string } str - the leftover parts of the input string
* @param { object } data - the data to store in the new node
*/
function _splitNode(node, prefix, str, data) {
var originalNode;
var oldIndex;
function _splitNode (node, prefix, str, data) {
var originalNode
var oldIndex
var children = node.children;
for (var i = 0; i < children.length; i++) {
if (children[i].path.startsWith(prefix)) {
originalNode = children[i];
oldIndex = i;
break;
}
var children = node.children
for (var i = 0; i < children.length; i++) {
if (children[i].path.startsWith(prefix)) {
originalNode = children[i]
oldIndex = i
break
}
}
var newLink = str.substring(prefix.length);
var oldLink = originalNode.path.substring(prefix.length);
var newLink = str.substring(prefix.length)
var oldLink = originalNode.path.substring(prefix.length)
// set new path
originalNode.path = oldLink;
var newNode = _buildNodeChain(newLink, data);
var intermediateNode = new Node(prefix);
// set new path
originalNode.path = oldLink
var newNode = _buildNodeChain(newLink, data)
var intermediateNode = new Node(prefix)
originalNode.parent = intermediateNode;
newNode.parent = intermediateNode;
intermediateNode.parent = node;
originalNode.parent = intermediateNode
newNode.parent = intermediateNode
intermediateNode.parent = node
intermediateNode.children.push(originalNode);
intermediateNode.children.push(newNode);
intermediateNode.children.push(originalNode)
intermediateNode.children.push(newNode)
node.children.push(intermediateNode);
node.children.push(intermediateNode)
// remove old node the list of children
node.children.splice(oldIndex, 1);
return newNode;
// remove old node the list of children
node.children.splice(oldIndex, 1)
return newNode
}

@@ -316,110 +313,130 @@

var EXACT_MATCH_HANDLERS = {
'insert': function(options) {
var node = options.node;
var prefix = options.prefix;
var str = options.str;
var data = options.data;
var childNode = _getChildNode(node, prefix);
childNode.data = data;
return node;
},
'delete': function(options) {
var parentNode = options.node;
var prefix = options.prefix;
var childNode = _getChildNode(parentNode, prefix);
if (childNode.children.length === 0) {
// delete node from parent
for (var i = 0; i < parentNode.children.length; i++) {
if (parentNode.children[i].path === prefix) {
break;
}
}
parentNode.children.splice(i, 1);
} else {
childNode.data = null;
'insert': function (options) {
var node = options.node
var prefix = options.prefix
var data = options.data
var childNode = _getChildNode(node, prefix)
childNode.data = data
return node
},
'remove': function (options) {
var parentNode = options.node
var prefix = options.prefix
var result = options.data
var childNode = _getChildNode(parentNode, prefix)
if (childNode.data) {
result.success = true
}
if (childNode.children.length === 0) {
// remove node from parent
for (var i = 0; i < parentNode.children.length; i++) {
if (parentNode.children[i].path === prefix) {
break
}
return childNode;
},
'lookup': function(options) {
var node = options.node;
var prefix = options.prefix;
var discoveredNode = _getChildNode(node, prefix);
return discoveredNode;
},
'startsWith': function(options) {
var node = options.node;
var prefix = options.prefix;
var str = options.str;
var childNode = _getChildNode(node, prefix);
if (childNode) {
return childNode;
}
parentNode.children.splice(i, 1)
if (parentNode.children.length === 1) {
var lastChildNode = parentNode.children[0]
if (parentNode.data && Object.keys(parentNode.data).length === 1) {
// no real data is associated with the parent
if (parentNode.type === NORMAL_NODE && parentNode.path !== '/' &&
lastChildNode.type === NORMAL_NODE && lastChildNode.path !== '/') {
// child node just a regular node, merge them together
parentNode.children = []
parentNode.path += lastChildNode.path
parentNode.data = lastChildNode.data
parentNode.data.path = parentNode.path
}
}
return _getAllPrefixChildren(node, prefix);
}
} else {
childNode.data = null
}
};
return childNode
},
'lookup': function (options) {
var node = options.node
var prefix = options.prefix
var discoveredNode = _getChildNode(node, prefix)
return discoveredNode
},
'startsWith': function (options) {
var node = options.node
var prefix = options.prefix
var childNode = _getChildNode(node, prefix)
if (childNode) {
return childNode
}
return _getAllPrefixChildren(node, prefix)
}
}
// handle situations where there is a partial match
var PARTIAL_MATCH_HANDLERS = {
'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);
return newNode;
},
'delete': function() {
return null;
},
'lookup': function() {
return null;
},
'startsWith': function(options) {
var node = options.node;
var prefix = options.prefix;
return _getAllPrefixChildren(node, prefix);
}
};
'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)
return newNode
},
'remove': function () {
return null
},
'lookup': function () {
return null
},
'startsWith': function (options) {
var node = options.node
var prefix = options.prefix
return _getAllPrefixChildren(node, prefix)
}
}
// handle situtations where there is no match
var NO_MATCH_HANDLERS = {
'insert': function(options) {
var parentNode = options.node;
var prefix = options.prefix;
var str = options.str;
var data = options.data;
var newNode = _buildNodeChain(str, data);
parentNode.children.push(newNode);
newNode.parent = parentNode;
return newNode;
},
'delete': function() {
return null;
},
'lookup': function() {
return null;
},
'startsWith': function() {
return [];
}
};
'insert': function (options) {
var parentNode = options.node
var str = options.str
var data = options.data
var newNode = _buildNodeChain(str, data)
parentNode.children.push(newNode)
newNode.parent = parentNode
return newNode
},
'remove': function () {
return null
},
'lookup': function () {
return null
},
'startsWith': function () {
return []
}
}
function _onPlaceholder(placeholderOptions) {
var options = placeholderOptions.options;
var childNode = options.node;
var parentNode = options.node.parent;
var str = options.str;
var data = options.data;
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);
if (options.str.length === 0) {
return options.onExactMatch({
node: parentNode,
prefix: childNode.path,
str: str,
data: data
})
}
return _traverse(options)
}

@@ -429,26 +446,27 @@

var PLACEHOLDER_HANDLERS = {
// lookup handles placeholders differently
'lookup': function(placeholderOptions) {
var key = placeholderOptions.key;
var param = placeholderOptions.param;
var options = placeholderOptions.options;
var data = options.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) {
data.params = {};
}
data.params[key] = param;
if (!data.params) {
data.params = {}
}
data.params[key] = param
if (options.str.length === 0) {
return options.node;
}
if (options.str.length === 0) {
return options.node
}
return _traverse(options);
},
// inserts shouldn't care about placeholders at all
'insert': null,
'delete': _onPlaceholder,
'startsWith': _onPlaceholder
};
return _traverse(options)
},
// inserts shouldn't care about placeholders at all
'insert': null,
'remove': _onPlaceholder,
'startsWith': _onPlaceholder
}
/**

@@ -459,24 +477,22 @@ * Helper method for retrieving all needed action handlers

*/
function _getHandlers(action) {
return {
onExactMatch: EXACT_MATCH_HANDLERS[action],
onPartialMatch: PARTIAL_MATCH_HANDLERS[action],
onNoMatch: NO_MATCH_HANDLERS[action],
onPlaceholder: PLACEHOLDER_HANDLERS[action]
};
function _getHandlers (action) {
return {
onExactMatch: EXACT_MATCH_HANDLERS[action],
onPartialMatch: PARTIAL_MATCH_HANDLERS[action],
onNoMatch: NO_MATCH_HANDLERS[action],
onPlaceholder: PLACEHOLDER_HANDLERS[action]
}
}
function _validateInput (input, strictPaths) {
var path = input
assert(path, '"path" must be provided')
assert(typeof path === 'string', '"path" must be that of a string')
function _validateInput(input, strictPaths) {
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
// allow for trailing slashes to match by removing it
if (!strictPaths && path.length > 1 && path[path.length - 1] === '/') {
path = path.slice(0, path.length - 1)
}
if (!strictPaths && path.length > 1 && path[path.length - 1] === '/') {
path = path.slice(0, path.length - 1);
}
return path;
return path
}

@@ -487,18 +503,18 @@

*
* @param {Node} rootNode - the node to start from
* @param {string} action - the action to perform, this will be used to get handlers
* @param {string} input - the string to use for traversal
* @param {object} data - the object to store in the Radix Tree
* @param { Node } rootNode - the node to start from
* @param { string } action - the action to perform, this will be used to get handlers
* @param { string } input - the string to use for traversal
* @param { object } data - the object to store in the Radix Tree
*/
function _startTraversal(rootNode, action, input, data) {
var handlers = _getHandlers(action);
return _traverse({
node: rootNode,
str: input,
onExactMatch: handlers.onExactMatch,
onPartialMatch: handlers.onPartialMatch,
onNoMatch: handlers.onNoMatch,
onPlaceholder: handlers.onPlaceholder,
data: data
});
function _startTraversal (rootNode, action, input, data) {
var handlers = _getHandlers(action)
return _traverse({
node: rootNode,
str: input,
onExactMatch: handlers.onExactMatch,
onPartialMatch: handlers.onPartialMatch,
onNoMatch: handlers.onNoMatch,
onPlaceholder: handlers.onPlaceholder,
data: data
})
}

@@ -510,8 +526,8 @@

*/
function Node(path, data, type) {
this.type = type || NORMAL_NODE;
this.path = path;
this.parent = undefined;
this.children = [];
this.data = data || null;
function Node (path, data, type) {
this.type = type || NORMAL_NODE
this.path = path
this.parent = undefined
this.children = []
this.data = data || null
}

@@ -523,53 +539,95 @@

*/
function RadixRouter(options) {
this._rootNode = new Node();
this._strictMode = !!options && options.strict;
// TODO: handle routes passed in via options
function RadixRouter (options) {
var self = this
self._rootNode = new Node()
self._strictMode = options && options.strict
// handle insertion of routes passed into constructor
var routes = options && options.routes
if (routes) {
routes.forEach(function (route) {
self.insert(route)
})
}
}
RadixRouter.prototype = {
lookup: function(input) {
var self = this;
var path = _validateInput(input, self._strictMode);
var result = {
path: input,
data: null
};
var node = _startTraversal(self._rootNode, 'lookup', path, result);
result.data = node ? node.data : null;
return result;
},
/**
* Perform lookup of given path in radix tree
* @param { string } path - the path to search for
*
* @returns { object } The data that was originally inserted into the tree
*/
lookup: function (path) {
var self = this
path = _validateInput(path, self._strictMode)
var data = {}
startsWith: function(prefix) {
var self = this;
_validateInput(prefix, self._strictMode);
var result = _startTraversal(self._rootNode, 'startsWith', prefix);
// find the node
var node = _startTraversal(self._rootNode, 'lookup', path, data)
var result = node && node.data
var resultArray = [];
if (result instanceof Node) {
_traverseDepths(result, prefix, resultArray);
} else {
result.forEach(function(child) {
_traverseDepths(child,
prefix.substring(0, prefix.indexOf(child.path[0])) + child.path,
resultArray);
});
}
return resultArray;
},
if (result && data.params) {
result.params = data.params
}
insert: function(input, data) {
var self = this;
var path = _validateInput(input, self._strictMode);
return _startTraversal(self._rootNode, 'insert', path, data);
},
return result
},
delete: function(input) {
var self = this;
var path = _validateInput(input, self._strictMode);
return _startTraversal(self._rootNode, 'delete', path);
/**
* Perform lookup of all paths that start with the given prefix
* @param { string } prefix - the prefix to match
*
* @returns { object[] } An array of matches along with any data that
* was originally passed in when inserted
*/
startsWith: function (prefix) {
var self = this
_validateInput(prefix, self._strictMode)
var result = _startTraversal(self._rootNode, 'startsWith', prefix)
var resultArray = []
if (result instanceof Node) {
_traverseDepths(result, prefix, resultArray)
} else {
result.forEach(function (child) {
_traverseDepths(child,
prefix.substring(0, prefix.indexOf(child.path[0])) + child.path,
resultArray)
})
}
};
return resultArray
},
module.exports = RadixRouter;
/**
* Perform an insert into the radix tree
* @param { string } data.path - the prefix to match
*
* Note: any other params attached to the data object will
* also be inserted as part of the node's data
*/
insert: function (data) {
var self = this
var path = data.path
path = _validateInput(path, self._strictMode)
_startTraversal(self._rootNode, 'insert', path, data)
},
/**
* Perform a remove on the tree
* @param { string } data.path - the route to match
*
* @returns { boolean } A boolean signifying if the remove was
* successful or not
*/
remove: function (path) {
var self = this
path = _validateInput(path, self._strictMode)
var result = { success: false }
_startTraversal(self._rootNode, 'remove', path, result)
return result.success
}
}
module.exports = RadixRouter

@@ -6,2 +6,6 @@ {

"coveralls": "^2.11.14",
"eslint": "^3.15.0",
"eslint-config-standard": "^6.2.1",
"eslint-plugin-promise": "^3.4.1",
"eslint-plugin-standard": "^2.0.1",
"git-hooks": "^1.1.6",

@@ -16,3 +20,3 @@ "istanbul": "^0.4.5",

"name": "radix-router",
"version": "0.1.6",
"version": "1.0.0",
"description": "Radix tree based router",

@@ -29,4 +33,5 @@ "main": "index.js",

"test-coverage": "istanbul cover _mocha --include-all-sources -- --ui bdd --reporter spec ./tests",
"coveralls": "cat ./coverage/lcov.info | coveralls"
"coveralls": "cat ./coverage/lcov.info | coveralls",
"lint": "eslint ."
}
}

@@ -10,12 +10,10 @@ # Radix Router

### Installation
```
```bash
npm install --save radix-router
```
better yet
```
yarn add radix-router
```
### Usage
#### Creating a new Router
`new RadixRouter(options)` - Creates a new instance of a router. The `options` object is optional.

@@ -25,81 +23,148 @@

- `routes` - The routes to insert into the router.
- `strict` - Setting this option to `true` will force lookups to match exact paths (trailing slashes will not be ignored). Defaults to `false`.
`insert(path, data)` - Adds the given path to the router and associates the given data with the path.
```js
const RadixRouter = require('radix-router')
`lookup(path)` - Performs a lookup of the path. If there is a match, the data associated with the route is returned.
const router = new RadixRouter({
strict: true,
routes: [
{
path: '/my/api/route/a', // "path" is a required field
// any other fields will also be stored by the router
extraRouteData: {},
description: 'this is a route'
},
{
path: '/my/api/route/b',
extraRouteData: {},
description: 'this is a different route',
routeBSpecificData: {}
}
]
})
```
`delete(path)` - Deletes the path from the router.
#### Router methods
`startsWith(prefix)` - Returns a map of all routes starting with the given prefix and the data associated with them.
##### `insert(routeData)`
### Example
Adds the given data to the router. The object passed in must contain a `path` attribute that is a string.
The `path` will be used by the router to know where to place the route.
Example input:
```js
router.insert({
path: '/api/route/c', // required
// any additional data goes here
extraData: 'anything can be added',
handler: function (req, res) {
// ...
}
})
```
const RadixRouter = require('radix-router');
let router = new RadixRouter({
strict: true
});
##### `lookup(path)`
router.insert('/api/v1/route', {
much: 'data'
});
Performs a lookup of the path. If there is a match, the data associated with the
route is returned, otherwise this will return `null`.
router.insert('/api/v2/**', {
such: 'wildcard'
});
Usage:
router.insert('/api/v1/other-route/:id', {
```js
const routeThatExists = router.lookup('/api/route/c')
```
Example output:
```js
{
path: '/api/route/c',
extraData: 'anything can be added',
handler: function (req, res) {
// ...
}
}
```
##### `remove(path)`
Removes the path from the router. Returns `true` if the route was found and removed.
Usage:
```
const routeRemoved = router.remove('/some/route')
```
##### `startsWith(path)`
Returns a map of all routes starting with the given prefix and the data associated with them.
Usage:
```
const apiRoutes = router.startsWith('/api')
```
Example output:
```js
[
{
path:'/api/v1/route',
much: 'data'
},
{
path: '/api/v1/other-route/:id',
so: 'placeholder',
much: 'wow'
});
}
]
```
router.lookup('/api/v1/route');
// returns {
// path: '/api/v1/route',
// data: {
// much: 'data'
// }
// }
### Wildcard and placeholder matching
router.lookup('/api/v2/anything/goes/here');
// returns {
// path: '/api/v2/anything/goes/here',
// data: {
// such: 'wildcard'
// }
// }
Wildcards can be added by to the end of routes by adding `/**` to the end of your route.
router.lookup('/api/v1/other-route/abcd');
// returns {
// path: '/api/v1/other-route/abcd',
// data: {
// so: 'placeholder',
// much: 'wow'
// },
// params: {
// id: 'abcd'
// }
// }
Example:
// remove route
router.delete('/api/v2/**');
```js
router.insert(
path: '/api/v2/**',
such: 'wildcard'
})
```
router.lookup('/api/v2/anything/goes/here');
// returns {
// path: '/api/v2/anything/goes/here',
// data: null
// }
Output of `router.lookup('/api/v2/some/random/route')`:
```js
{
path: '/api/v2/**',
sucn: 'wildcard'
}
```
route.startsWith('/api')
// returns {
// '/api/v1/route': {
// much: 'data'
// },
// '/api/v1/other-route/:id': {
// so: 'placeholder',
// much: 'wow'
// }
// }
Placeholders can be used in routes by starting a segment of the route with a colon `:`. Whatever
content fills the position of the placeholder will be added to the lookup result
under the `params` attribute.
Example:
```js
router.insert(
path: '/api/v2/:myPlaceholder/route',
very: 'placeholder'
})
```
Output of `router.lookup('/api/v2/application/route')`:
```js
{
path: '/api/v2/:myPlaceholder/route',
very: 'placeholder',
params: {
myPlaceholder: 'application'
}
}
```

@@ -1,173 +0,164 @@

const {expect} = require('chai');
const RadixRouter = require('../index');
var expect = require('chai').expect
var RadixRouter = require('../index')
var _putRoute = require('./util/putRoute')
describe('Router lookup', () => {
it('should be able lookup static routes', () => {
let router = new RadixRouter();
describe('Router lookup', function () {
it('should be able lookup static routes', function () {
var router = new RadixRouter()
router.insert('/', true);
router.insert('/route', true);
router.insert('/another-route', true);
router.insert('/this/is/yet/another/route', true);
_putRoute(router, '/', true)
_putRoute(router, '/route', true)
_putRoute(router, '/another-route', true)
_putRoute(router, '/this/is/yet/another/route', true)
expect(router.lookup('/')).to.deep.equal({
path: '/',
data: true
});
expect(router.lookup('/')).to.deep.equal({
path: '/',
data: true
})
expect(router.lookup('/route')).to.deep.equal({
path: '/route',
data: true
});
expect(router.lookup('/another-route')).to.deep.equal({
path: '/another-route',
data: true
});
expect(router.lookup('/this/is/yet/another/route')).to.deep.equal({
path: '/this/is/yet/another/route',
data: true
});
});
expect(router.lookup('/route')).to.deep.equal({
path: '/route',
data: true
})
expect(router.lookup('/another-route')).to.deep.equal({
path: '/another-route',
data: true
})
expect(router.lookup('/this/is/yet/another/route')).to.deep.equal({
path: '/this/is/yet/another/route',
data: true
})
})
it('should be able to retrieve placeholders', () => {
let router = new RadixRouter();
router.insert('carbon/:element', 14);
router.insert('carbon/:element/test/:testing', 15);
router.insert('this/:route/has/:cool/stuff', 16);
it('should be able to retrieve placeholders', function () {
var router = new RadixRouter()
_putRoute(router, 'carbon/:element', 14)
_putRoute(router, 'carbon/:element/test/:testing', 15)
_putRoute(router, 'this/:route/has/:cool/stuff', 16)
expect(router.lookup('carbon/test1')).to.deep.equal({
path: 'carbon/test1',
data: 14,
params: {
'element': 'test1'
}
});
expect(router.lookup('carbon/test1')).to.deep.equal({
path: 'carbon/test1',
data: 14,
params: {
'element': 'test1'
}
});
expect(router.lookup('carbon/test2/test/test23')).to.deep.equal({
path: 'carbon/test2/test/test23',
data: 15,
params: {
'element': 'test2',
'testing': 'test23'
}
});
expect(router.lookup('this/test/has/more/stuff')).to.deep.equal({
path: 'this/test/has/more/stuff',
data: 16,
params: {
route: 'test',
cool: 'more'
}
});
});
expect(router.lookup('carbon/test1')).to.deep.equal({
path: 'carbon/:element',
data: 14,
params: {
'element': 'test1'
}
})
expect(router.lookup('carbon/test1')).to.deep.equal({
path: 'carbon/:element',
data: 14,
params: {
'element': 'test1'
}
})
expect(router.lookup('carbon/test2/test/test23')).to.deep.equal({
path: 'carbon/:element/test/:testing',
data: 15,
params: {
'element': 'test2',
'testing': 'test23'
}
})
expect(router.lookup('this/test/has/more/stuff')).to.deep.equal({
path: 'this/:route/has/:cool/stuff',
data: 16,
params: {
route: 'test',
cool: 'more'
}
})
})
it('should be able to perform wildcard lookups', () => {
let router = new RadixRouter();
it('should be able to perform wildcard lookups', function () {
var router = new RadixRouter()
router.insert('polymer/**', 12);
router.insert('polymer/another/route', 13);
_putRoute(router, 'polymer/**', 12)
_putRoute(router, 'polymer/another/route', 13)
expect(router.lookup('polymer/another/route')).to.deep.equal({
path: 'polymer/another/route',
data: 13
});
expect(router.lookup('polymer/another/route')).to.deep.equal({
path: 'polymer/another/route',
data: 13
})
expect(router.lookup('polymer/anon')).to.deep.equal({
path: 'polymer/anon',
data: 12
});
expect(router.lookup('polymer/anon')).to.deep.equal({
path: 'polymer/**',
data: 12
})
expect(router.lookup('polymer/2415')).to.deep.equal({
path: 'polymer/2415',
data: 12
});
expect(router.lookup('polymer/2415')).to.deep.equal({
path: 'polymer/**',
data: 12
})
})
});
it('should be able to match routes with trailing slash', function () {
var router = new RadixRouter()
it('should be able to match routes with trailing slash', () => {
let router = new RadixRouter();
_putRoute(router, 'route/without/trailing/slash', true)
_putRoute(router, 'route/with/trailing/slash/', true)
router.insert('route/without/trailing/slash', true);
router.insert('route/with/trailing/slash/', true);
expect(router.lookup('route/without/trailing/slash')).to.deep.equal({
path: 'route/without/trailing/slash',
data: true
})
expect(router.lookup('route/without/trailing/slash')).to.deep.equal({
path: 'route/without/trailing/slash',
data: true
});
expect(router.lookup('route/without/trailing/slash/')).to.deep.equal({
path: 'route/without/trailing/slash',
data: true
})
expect(router.lookup('route/without/trailing/slash/')).to.deep.equal({
path: 'route/without/trailing/slash/',
data: true
});
expect(router.lookup('route/with/trailing/slash')).to.deep.equal({
path: 'route/with/trailing/slash/',
data: true
})
expect(router.lookup('route/with/trailing/slash')).to.deep.equal({
path: 'route/with/trailing/slash',
data: true
});
expect(router.lookup('route/with/trailing/slash/')).to.deep.equal({
path: 'route/with/trailing/slash/',
data: true
})
})
expect(router.lookup('route/with/trailing/slash/')).to.deep.equal({
path: 'route/with/trailing/slash/',
data: true
});
it('should not match routes with trailing slash if router is created with strict mode', function () {
var router = new RadixRouter({
strict: true
})
});
_putRoute(router, '/', 1)
_putRoute(router, '//', 2)
_putRoute(router, '///', 3)
_putRoute(router, '////', 4)
_putRoute(router, 'route/without/trailing/slash', true)
_putRoute(router, 'route/with/trailing/slash/', true)
it('should not match routes with trailing slash if router is created with strict mode', () => {
let router = new RadixRouter({
strict: true
});
expect(router.lookup('/')).to.deep.equal({
path: '/',
data: 1
})
router.insert('/', 1);
router.insert('//', 2);
router.insert('///', 3);
router.insert('////', 4);
router.insert('route/without/trailing/slash', true);
router.insert('route/with/trailing/slash/', true);
expect(router.lookup('//')).to.deep.equal({
path: '//',
data: 2
})
expect(router.lookup('/')).to.deep.equal({
path: '/',
data: 1
});
expect(router.lookup('///')).to.deep.equal({
path: '///',
data: 3
})
expect(router.lookup('//')).to.deep.equal({
path: '//',
data: 2
});
expect(router.lookup('////')).to.deep.equal({
path: '////',
data: 4
})
expect(router.lookup('///')).to.deep.equal({
path: '///',
data: 3
});
expect(router.lookup('route/without/trailing/slash')).to.deep.equal({
path: 'route/without/trailing/slash',
data: true
})
expect(router.lookup('////')).to.deep.equal({
path: '////',
data: 4
});
expect(router.lookup('route/without/trailing/slash')).to.deep.equal({
path: 'route/without/trailing/slash',
data: true
});
expect(router.lookup('route/without/trailing/slash/')).to.deep.equal({
path: 'route/without/trailing/slash/',
data: null
});
expect(router.lookup('route/with/trailing/slash')).to.deep.equal({
path: 'route/with/trailing/slash',
data: null
});
expect(router.lookup('route/with/trailing/slash/')).to.deep.equal({
path: 'route/with/trailing/slash/',
data: true
});
});
});
expect(router.lookup('route/without/trailing/slash/')).to.deep.equal(null)
expect(router.lookup('route/with/trailing/slash')).to.deep.equal(null)
expect(router.lookup('route/with/trailing/slash/')).to.deep.equal({
path: 'route/with/trailing/slash/',
data: true
})
})
})

@@ -1,33 +0,35 @@

const {expect} = require('chai');
const RadixRouter = require('../index');
var expect = require('chai').expect
var RadixRouter = require('../index')
var _putRoute = require('./util/putRoute')
function containsPath(array, path) {
for (let i = 0; i < array.length; i++) {
if (array[i].path === path) {
return true;
}
function containsPath (array, path, data) {
for (var i = 0; i < array.length; i++) {
if (array[i].path === path && array[i].data === data) {
return true
}
return false;
}
return false
}
describe('Router startsWith', () => {
it('should be able retrieve all results via prefix', () => {
let router = new RadixRouter();
router.insert('hello', 1);
router.insert('hi', 2);
router.insert('helium', 3);
router.insert('chrome', 6);
router.insert('choot', 7);
router.insert('chromium', 8);
let setA = router.startsWith('h');
expect(setA.length).to.equal(3);
expect(containsPath(setA, 'hello')).to.equal(true);
expect(containsPath(setA, 'hi')).to.equal(true);
expect(containsPath(setA, 'helium')).to.equal(true);
describe('Router startsWith', function () {
it('should be able retrieve all results via prefix', function () {
var router = new RadixRouter()
_putRoute(router, 'hello', 1)
_putRoute(router, 'hi', 2)
_putRoute(router, 'helium', 3)
_putRoute(router, 'chrome', 6)
_putRoute(router, 'choot', 7)
_putRoute(router, 'chromium', 8)
let setB = router.startsWith('c');
expect(containsPath(setB, 'chrome')).to.equal(true);
expect(containsPath(setB, 'choot')).to.equal(true);
expect(containsPath(setB, 'chromium')).to.equal(true);
});
});
var setA = router.startsWith('h')
expect(setA.length).to.equal(3)
expect(containsPath(setA, 'hello', 1)).to.equal(true)
expect(containsPath(setA, 'hi', 2)).to.equal(true)
expect(containsPath(setA, 'helium', 3)).to.equal(true)
var setB = router.startsWith('c')
expect(containsPath(setB, 'chrome', 6)).to.equal(true)
expect(containsPath(setB, 'choot', 7)).to.equal(true)
expect(containsPath(setB, 'chromium', 8)).to.equal(true)
})
})

@@ -1,76 +0,193 @@

const {expect} = require('chai');
var expect = require('chai').expect
var RadixRouter = require('../index')
var _putRoute = require('./util/putRoute')
let RadixRouter = require('../index');
function getChild(node, prefix) {
for (var i = 0; i < node.children.length; i++) {
if (node.children[i].path === prefix) {
return node.children[i];
}
function _getChild (node, prefix) {
for (var i = 0; i < node.children.length; i++) {
if (node.children[i].path === prefix) {
return node.children[i]
}
return null;
}
return null
}
const WILDCARD_TYPE = 1;
const PLACEHOLDER_TYPE = 2;
var WILDCARD_TYPE = 1
var PLACEHOLDER_TYPE = 2
describe('Router tree structure', () => {
it('should be able to insert nodes correctly into the tree', () => {
let router = new RadixRouter();
router.insert('hello');
router.insert('cool');
router.insert('hi');
router.insert('helium');
router.insert('coooool');
router.insert('chrome');
router.insert('choot');
/**
* Expected structure:
* root
* / \
* h c
* / \ / \
* i el oo h
* / \ / \ / \
* lo ium l oool rome oot
*/
describe('Router tree structure', function () {
it('should be able to insert nodes correctly into the tree', function () {
var router = new RadixRouter()
_putRoute(router, 'hello')
_putRoute(router, 'cool')
_putRoute(router, 'hi')
_putRoute(router, 'helium')
_putRoute(router, 'coooool')
_putRoute(router, 'chrome')
_putRoute(router, 'choot')
_putRoute(router, '/choot')
_putRoute(router, '//choot')
/**
* Expected structure:
* root
* / \
* h c
* / \ / \
* i el oo h
* / \ / \ / \
* lo ium l oool rome oot
*/
let h_node = getChild(router._rootNode, 'h');
let i_node = getChild(h_node, 'i');
let el_node = getChild(h_node, 'el');
expect(h_node.children.length).to.equal(2);
expect(i_node.path).to.not.equal(null);
expect(el_node.children.length).to.equal(2);
expect(getChild(el_node, 'lo').path).to.not.equal(null);
expect(getChild(el_node, 'ium').path).to.not.equal(null);
var hNode = _getChild(router._rootNode, 'h')
var iNode = _getChild(hNode, 'i')
var elNode = _getChild(hNode, 'el')
expect(hNode.children.length).to.equal(2)
expect(iNode.path).to.not.equal(null)
expect(elNode.children.length).to.equal(2)
expect(_getChild(elNode, 'lo').path).to.not.equal(null)
expect(_getChild(elNode, 'ium').path).to.not.equal(null)
let c_node = getChild(router._rootNode, 'c');
let oo_node = getChild(c_node, 'oo');
let h2_node = getChild(c_node, 'h');
expect(oo_node.children.length).to.equal(2);
expect(h2_node.children.length).to.equal(2);
expect(getChild(oo_node, 'l')).to.not.equal(null);
expect(getChild(oo_node, 'oool')).to.not.equal(null);
var cNode = _getChild(router._rootNode, 'c')
var ooNode = _getChild(cNode, 'oo')
var h2Node = _getChild(cNode, 'h')
expect(ooNode.children.length).to.equal(2)
expect(h2Node.children.length).to.equal(2)
expect(_getChild(ooNode, 'l')).to.not.equal(null)
expect(_getChild(ooNode, 'oool')).to.not.equal(null)
expect(getChild(h2_node, 'rome')).to.not.equal(null);
expect(getChild(h2_node, 'oot')).to.not.equal(null);
});
expect(_getChild(h2Node, 'rome')).to.not.equal(null)
expect(_getChild(h2Node, 'oot')).to.not.equal(null)
})
it('insert placeholder and wildcard nodes correctly into the tree', () => {
let router = new RadixRouter();
router.insert('hello/:placeholder/tree');
router.insert('choot/choo/**');
it('should insert placeholder and wildcard nodes correctly into the tree', function () {
var router = new RadixRouter()
_putRoute(router, 'hello/:placeholder/tree')
_putRoute(router, 'choot/choo/**')
let hello_node = getChild(router._rootNode, 'hello');
let hello_slash_node = getChild(hello_node, '/');
let hello_slash_placeholder_node = getChild(hello_slash_node, ':placeholder');
expect(hello_slash_placeholder_node.type).to.equal(PLACEHOLDER_TYPE);
var helloNode = _getChild(router._rootNode, 'hello')
var helloSlashNode = _getChild(helloNode, '/')
var helloSlashPlaceholderNode = _getChild(helloSlashNode, ':placeholder')
expect(helloSlashPlaceholderNode.type).to.equal(PLACEHOLDER_TYPE)
let choot_node = getChild(router._rootNode, 'choot');
let choot_slash_node = getChild(choot_node, '/');
let choot_slash_choo_node = getChild(choot_slash_node, 'choo');
let choot_slash_choo_slash_node = getChild(choot_slash_choo_node, '/');
let choot_slash_choo_slash_wildcard_node = getChild(choot_slash_choo_slash_node, '**');
expect(choot_slash_choo_slash_wildcard_node.type).to.equal(WILDCARD_TYPE);
});
});
var chootNode = _getChild(router._rootNode, 'choot')
var chootSlashNode = _getChild(chootNode, '/')
var chootSlashChooNode = _getChild(chootSlashNode, 'choo')
var chootSlashChooSlashNode = _getChild(chootSlashChooNode, '/')
var chootSlashChooSlashWildcardNode = _getChild(chootSlashChooSlashNode, '**')
expect(chootSlashChooSlashWildcardNode.type).to.equal(WILDCARD_TYPE)
})
it('should throw an error if a path is not supplied when inserting a route', function () {
var router = new RadixRouter()
var insert = router.insert.bind(router, {
notAPath: 'this is not a path'
})
expect(insert).to.throw(/"path" must be provided/)
})
it('should be able to initialize routes via the router contructor', function () {
var router = new RadixRouter({
routes: [
{ path: '/api/v1', value: 1 },
{ path: '/api/v2', value: 2 },
{ path: '/api/v3', value: 3 }
]
})
var rootSlashNode = _getChild(router._rootNode, '/')
var apiNode = _getChild(rootSlashNode, 'api')
var apiSlashNode = _getChild(apiNode, '/')
var vNode = _getChild(apiSlashNode, 'v')
var v1Node = _getChild(vNode, '1')
var v2Node = _getChild(vNode, '2')
var v3Node = _getChild(vNode, '3')
expect(v1Node).to.exist
expect(v2Node).to.exist
expect(v3Node).to.exist
expect(v1Node.data.value).to.equal(1)
expect(v2Node.data.value).to.equal(2)
expect(v3Node.data.value).to.equal(3)
})
it('should throw an error if a path is not supplied when inserting a route via constructor', function () {
function createRouter () {
return new RadixRouter({
routes: [
{ path: '/api/v1' },
{ notAPath: '/api/v2' }
]
})
}
expect(createRouter).to.throw(/"path" must be provided/)
})
context('upon removal of route', function () {
it('should merge childNodes left with no siblings with parent if parent contains no data', function () {
var router = new RadixRouter()
router.insert({ path: 'thisIsA' })
router.insert({ path: 'thisIsAnotherRoute', value: 1 })
router.insert({ path: 'thisIsAboutToGetDeleted' })
var baseNode = _getChild(router._rootNode, 'thisIsA')
var anotherRouteNode = _getChild(baseNode, 'notherRoute')
var aboutToGetDeletedNode = _getChild(baseNode, 'boutToGetDeleted')
expect(anotherRouteNode).to.exist
expect(aboutToGetDeletedNode).to.exist
router.remove('thisIsAboutToGetDeleted')
var newBaseNode = _getChild(router._rootNode, 'thisIsAnotherRoute')
expect(newBaseNode).to.exist
expect(newBaseNode.data.value).to.equal(1)
expect(newBaseNode.data.path).to.equal('thisIsAnotherRoute')
})
it('should NOT merge childNodes left with no siblings with parent if contains data', function () {
var router = new RadixRouter()
router.insert({ path: 'thisIsA', data: 1 })
router.insert({ path: 'thisIsAnotherRoute' })
router.insert({ path: 'thisIsAboutToGetDeleted' })
var baseNode = _getChild(router._rootNode, 'thisIsA')
var anotherRouteNode = _getChild(baseNode, 'notherRoute')
var aboutToGetDeletedNode = _getChild(baseNode, 'boutToGetDeleted')
expect(anotherRouteNode).to.exist
expect(aboutToGetDeletedNode).to.exist
router.remove('thisIsAboutToGetDeleted')
var newBaseNode = _getChild(router._rootNode, 'thisIsAnotherRoute')
expect(newBaseNode).to.not.exist
var originalBaseNode = _getChild(router._rootNode, 'thisIsA')
expect(originalBaseNode).to.exist
var originalAnotherRouteNode = _getChild(baseNode, 'notherRoute')
expect(originalAnotherRouteNode).to.exist
})
it('should merge childNodes with parent if parent is a slash separator', function () {
var router = new RadixRouter()
router.insert({ path: 'thisIsA/', data: 1 })
router.insert({ path: 'thisIsA/notherRoute' })
router.insert({ path: 'thisIsA/boutToGetDeleted' })
var baseNode = _getChild(router._rootNode, 'thisIsA')
var slashNode = _getChild(baseNode, '/')
var anotherRouteNode = _getChild(slashNode, 'notherRoute')
var aboutToGetDeletedNode = _getChild(slashNode, 'boutToGetDeleted')
expect(anotherRouteNode).to.exist
expect(aboutToGetDeletedNode).to.exist
router.remove('thisIsA/boutToGetDeleted')
var originalBaseNode = _getChild(router._rootNode, 'thisIsA')
expect(originalBaseNode).to.exist
var originalAnotherRouteNode = _getChild(slashNode, 'notherRoute')
expect(originalAnotherRouteNode).to.exist
})
})
})

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc