expand method

String expand(
  1. Map<String, Object?> variables
)

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();
}