uri-template-router
Version:
Match a URI to a pattern in a collection of URI Templates
192 lines (180 loc) • 6.62 kB
JavaScript
const { Router } = uriTemplateRouter;
var router;
function refreshRouter(){
router = new Router;
var errors = [];
document.getElementById('templates').value.split('\n').forEach(function(v){
const uriTemplate = v.trim();
if(!uriTemplate) return;
try {
router.addTemplate(uriTemplate);
}catch(err){
errors.push(err);
}
});
if(errors.length){
document.getElementById('router-status').textContent = errors.map(function(err){
return err.toString();
}).join('\n');
}else{
document.getElementById('router-status').textContent = router.size + ' routes parsed';
}
}
function refreshResults(){
if(!router) refreshRouter();
var input = document.getElementById('test').value;
var outTemplate = document.getElementById('result-template');
var outParams = document.getElementById('result-params');
var results = router.resolveURI(input);
var result = results;
if(result){
outTemplate.textContent = '<'+result.template+'>'+(result.argument||'');
outParams.textContent = Object.keys(result.params).map(function(v){
return v + " = " + JSON.stringify(result.params[v], null, '\t');
}).join("\n");
}else{
outTemplate.textContent = '';
outParams.textContent = 'Not Found';
}
var resultList = document.getElementById('result-list');
resultList.textContent = '';
for(var resultItem = result; resultItem; resultItem=resultItem.next()){
var li = document.createElement('li');
li.textContent = resultItem.template + ' ⟵ ' + JSON.stringify(resultItem.params);
resultList.appendChild(li);
}
document.getElementById('result-graph').textContent = toViz(router.fsm);
const header = document.getElementById('sort-header');
const tbody = document.getElementById('sort-tbody');
if(header){
header.innerHTML = '<th>×</th>';
tbody.innerHTML = '';
router.routes.forEach(function(left){
const right_th = document.createElement('th');
right_th.textContent = left.uriTemplate;
header.appendChild(right_th);
const left_tr = document.createElement('tr');
tbody.appendChild(left_tr);
const left_th = document.createElement('th');
left_th.textContent = left.uriTemplate;
tbody.appendChild(left_th);
router.routes.forEach(function(right){
const compare_res = left.compare(right);
const td = document.createElement('th');
if(compare_res[0]===true && compare_res[1]===true){
// Equal
td.textContent = '=';
}else if(compare_res[0]===true && compare_res[1]===false){
// Strict superset
td.textContent = '⊃';
}else if(compare_res[0]===false && compare_res[1]===true){
// Strict subset
td.textContent = '⊂';
}else if(compare_res[0]===false && compare_res[1]===false && compare_res[2]===true){
// No items in common
td.textContent = '≠';
}else if(compare_res[0]===false && compare_res[1]===false && compare_res[2]===false){
// There is an overlap
td.textContent = '∩';
}else{
td.textContent = compare_res;
}
tbody.appendChild(td);
});
});
}
const hierarchyTree = document.getElementById('hierarchy-tree');
if(hierarchyTree){
hierarchyTree.innerHTML = '';
const parents = [ {element: document.getElementById('hierarchy-tree'), children:router.hierarchy.children} ];
for(var i=0; i<parents.length; i++){
const trunk = document.createElement('ul');
for(var j=0; j<parents[i].children.length; j++){
const item = document.createElement('li');
item.textContent = parents[i].children[j].uriTemplate;
trunk.appendChild(item);
if(parents[i].children[j].children.length){
parents.push({ element: item, children: parents[i].children[j].children });
}
}
parents[i].element.appendChild(trunk);
}
}
}
function alot(){
router = new Router;
var pieces = [
['http://', 'https://'],
['', 'www.', 'subdomain.', 'users.', 'status.', 'about.', 'news.'],
['google','youtube', 'facebook', 'bidau', 'wikipedia', 'yahoo', 'qq',
'taobao', 'twitter', 'amazon', 'tmall', 'souhu', 'live', 'vk', 'instagram',
'linkedin', 'gmail', 'netflix', 't', 'ebay', 'pornhub', 'bing',
'msn', 'imgur', 'reddit', 'microsoft', 'twitch', 'tumblr', 'slashdot', 'ycombinator',
'github', 'cnn', 'foxnews', 'deviantart', 'example',
],
['.'],
['com', 'org', 'net', 'co', 'io', 'xyz', 'luxury', 'jp', 'cn', 'tv'],
['/', '/index', '/page/{id}', '/user/{id}', '/blog{/yyyy,mm,dd,slug}', '/~{user}', '/listing/{id}',
'/cart', '/status','/path{/path*}', '/{?x,y}'
],
['', '.html', '.json', '.txt', '.xml'],
];
var patterns = pieces.reduce(function(state, list){
var copy = [];
state.forEach(function(base){
list.forEach(function(segment){
copy.push(base+segment);
})
});
return copy;
}, ['']);
patterns.forEach(function(template){
console.log(template);
router.addTemplate(template);
});
console.log('Added '+patterns.length+' templates');
}
function toViz(transitions, history){
var highlight = new Set();
if(history){
var start = 0;
history.forEach(function(node){
highlight.add(`${start} ${node.symbol} ${node.nextStateId}`);
start = node.nextStateId;
});
}
var str = '';
str += 'digraph G {\n';
str += '\t_initial [shape=point];\n';
str += '\t_initial -> 0;\n';
transitions.forEach(function(state, id){
const final = state.final ? ' [shape=doublecircle]' : '';
str += '\t'+id+final+';\n';
for(const symbol in state.transitions){
const target = state.transitions[symbol];
const penwidth = highlight.has(`${id} ${symbol} ${target}`) ? ',penwidth=3' : '' ;
str += '\t'+id+' -> '+target+' [label='+JSON.stringify(symbol)+penwidth+'];\n';
}
if(state.final && Array.isArray(state.final)) state.final.forEach(function(final){
str += '\t'+JSON.stringify('final_'+final)+' [shape='+JSON.stringify('doublebox')+',label='+JSON.stringify(final.toString())+'];\n';
str += '\t'+id+' -> '+JSON.stringify('final_'+final)+' [dir=both,arrowtail=odot,arrowhead=o];\n';
});
// if(state.partials) for(const k in state.partials){
// const partial = state.partials[k];
// str += '\t'+JSON.stringify('final_'+k)+' [shape='+JSON.stringify('doublebox')+',label='+JSON.stringify(k+JSON.stringify(partial))+'];\n';
// str += '\t'+id+' -> '+JSON.stringify('final_'+k)+' [dir=both,arrowtail=odot,arrowhead=o,style=dashed];\n';
// };
});
str += '}\n';
return str;
}
window.onload = function(){
document.getElementById('templates').onchange = function(){
refreshRouter();
refreshResults();
};
document.getElementById('test').onchange = refreshResults;
document.getElementById('test').onkeyup = refreshResults;
refreshRouter();
refreshResults();
}