blob: 069aeb79465314f40f35e350e291c70269973b30 [file] [log] [blame]
library url_template;
import 'url_matcher.dart';
final _specialChars = new RegExp(r'[\\()$^.+[\]{}|]');
final _paramPattern = r'([^/?]+)';
/**
* A reversible URL template class that can match/parse and reverse URL
* templates like: /foo/:bar/baz
*/
class UrlTemplate implements UrlMatcher {
List<String> _fields;
RegExp _pattern;
String _strPattern;
List _chunks;
String toString() => '$_pattern';
int compareTo(UrlMatcher other) {
final String tmpParamPattern = '\t';
if (other is UrlTemplate) {
String thisPattern = _strPattern.replaceAll(_paramPattern, tmpParamPattern);
String otherPattern = other._strPattern.replaceAll(_paramPattern, tmpParamPattern);
List<String> thisPatternParts = thisPattern.split('/');
List<String> otherPatternParts = otherPattern.split('/');
if (thisPatternParts.length == otherPatternParts.length) {
for (int i = 0; i < thisPatternParts.length; i++) {
String thisPart = thisPatternParts[i];
String otherPart = otherPatternParts[i];
if (thisPart == tmpParamPattern && otherPart != tmpParamPattern) {
return 1;
} else if (thisPart != tmpParamPattern && otherPart == tmpParamPattern) {
return -1;
}
}
return otherPattern.compareTo(thisPattern);
} else {
return otherPatternParts.length - thisPatternParts.length;
}
} else {
return 0;
}
}
UrlTemplate(String template) {
_compileTemplate(template);
}
void _compileTemplate(String template) {
template = template.
replaceAllMapped(_specialChars, (m) => r'\' + m.group(0));
_fields = <String>[];
_chunks = [];
var exp = new RegExp(r':(\w+)');
StringBuffer sb = new StringBuffer('^');
int start = 0;
exp.allMatches(template).forEach((Match m) {
var paramName = m.group(1);
var txt = template.substring(start, m.start);
_fields.add(paramName);
_chunks.add(txt);
_chunks.add((Map params) => params != null ? params[paramName] : null);
sb.write(txt);
sb.write(_paramPattern);
start = m.end;
});
if (start != template.length) {
var txt = template.substring(start, template.length);
sb.write(txt);
_chunks.add(txt);
}
_strPattern = sb.toString();
_pattern = new RegExp(_strPattern);
}
UrlMatch match(String url) {
var matches = _pattern.allMatches(url);
if (matches.isEmpty) return null;
var parameters = new Map();
Match match = matches.first;
for (var i = 0; i < match.groupCount; i++) {
parameters[_fields[i]] = match.group(i + 1);
}
var tail = url.substring(match.group(0).length);
return new UrlMatch(match.group(0), tail, parameters);
}
String reverse({Map parameters, String tail: ''}) =>
_chunks.map((c) => c is Function ? c(parameters) : c).join() + tail;
List<String> urlParameterNames() => _fields;
}