expand method
Expands the template into a URI according to the rules specified in RFC 6570. Throws a ParseException if the template is invalid.
Implementation
String expand(Map<String, Object?> variables) {
final sb = StringBuffer();
for (var part in _parts) {
if (part is Match) {
final match = part;
final expr = match.group(3)!;
final op = match.group(2)!;
final separator = ['', '+', '#'].contains(op)
? ','
: (op == '?')
? '&'
: op;
final formStyle = [';', '?', '&'].contains(op);
final allowReserved = ['+', '#'].contains(op);
final result = expr
.split(',')
.map((String varspec) {
var varname = varspec;
var prefixLength = 0;
final prefixModIndex = varspec.lastIndexOf(':');
if (prefixModIndex != -1) {
varname = varspec.substring(0, prefixModIndex);
prefixLength = int.parse(varspec.substring(prefixModIndex + 1));
}
final explode = varspec[varspec.length - 1] == '*';
if (explode) {
varname = varspec.substring(0, varspec.length - 1);
}
var itemSeparator = explode ? separator : ',';
final value = variables[varname];
String? str;
if (value is Iterable) {
if (prefixLength != 0) throw ParseException(expr);
if (value.isNotEmpty) {
if (explode && formStyle) {
itemSeparator = '$itemSeparator$varname=';
}
str = value
.map((i) => _encode('$i', allowReserved))
.join(itemSeparator);
if (formStyle) str = '$varname=$str';
}
} else if (value is Map<String, Object?>) {
if (prefixLength != 0) throw ParseException(expr);
if (value.isNotEmpty) {
final kvSeparator = explode ? '=' : ',';
str = value.keys
.map((k) =>
_encode(k) +
kvSeparator +
_encode('${value[k]}', allowReserved))
.join(itemSeparator);
if (formStyle && !explode) str = '$varname=$str';
}
} else if (value != null) {
str = '$value';
if (prefixLength > 0 && prefixLength < str.length) {
str = str.substring(0, prefixLength);
}
str = _encode(str, allowReserved);
if (formStyle) {
str = (str.isEmpty && op == ';') ? varname : '$varname=$str';
}
}
return str;
})
.where((e) => e != null)
.toList(growable: false);
if (result.isNotEmpty) {
if (!(op == '' || op == '+')) {
sb.write(op);
}
sb.writeAll(result, separator);
}
} else {
sb.write(_encode(part as String, true));
}
}
return sb.toString();
}