encode static method

String encode(
  1. Object? object, [
  2. EncodeOptions options = const EncodeOptions()
])

Encodes an Object into a query String. Providing custom options will override the default behavior.

Implementation

static String encode(
  Object? object, [
  EncodeOptions options = const EncodeOptions(),
]) {
  if (object == null) {
    return '';
  }

  Map<String, dynamic> obj = switch (object) {
    Map<String, dynamic> map => {...map},
    Iterable iterable => iterable
        .toList()
        .asMap()
        .map((int k, dynamic v) => MapEntry(k.toString(), v)),
    _ => <String, dynamic>{},
  };

  final List keys = [];

  if (obj.isEmpty) {
    return '';
  }

  List? objKeys;

  if (options.filter is Function) {
    obj = options.filter?.call('', obj);
  } else if (options.filter is Iterable) {
    objKeys = List.of(options.filter);
  }

  objKeys ??= obj.keys.toList();

  if (options.sort is Function) {
    objKeys.sort(options.sort);
  }

  final WeakMap sideChannel = WeakMap();
  for (int i = 0; i < objKeys.length; i++) {
    final key = objKeys[i];

    if (key is! String? || (obj[key] == null && options.skipNulls)) {
      continue;
    }

    final encoded = _$Encode._encode(
      obj[key],
      undefined: !obj.containsKey(key),
      prefix: key,
      generateArrayPrefix: options.listFormat.generator,
      commaRoundTrip:
          options.listFormat.generator == ListFormat.comma.generator &&
              options.commaRoundTrip == true,
      allowEmptyLists: options.allowEmptyLists,
      strictNullHandling: options.strictNullHandling,
      skipNulls: options.skipNulls,
      encodeDotInKeys: options.encodeDotInKeys,
      encoder: options.encode ? options.encoder : null,
      serializeDate: options.serializeDate,
      filter: options.filter,
      sort: options.sort,
      allowDots: options.allowDots,
      format: options.format,
      formatter: options.formatter,
      encodeValuesOnly: options.encodeValuesOnly,
      charset: options.charset,
      addQueryPrefix: options.addQueryPrefix,
      sideChannel: sideChannel,
    );

    if (encoded is Iterable) {
      keys.addAll(encoded);
    } else {
      keys.add(encoded);
    }
  }

  final String joined = keys.join(options.delimiter);
  final StringBuffer out = StringBuffer();

  if (options.addQueryPrefix) {
    out.write('?');
  }

  if (options.charsetSentinel) {
    out.write(switch (options.charset) {
      /// encodeURIComponent('&#10003;')
      /// the "numeric entity" representation of a checkmark
      latin1 => '${Sentinel.iso}&',

      /// encodeURIComponent('✓')
      utf8 => '${Sentinel.charset}&',
      _ => '',
    });
  }

  if (joined.isNotEmpty) {
    out.write(joined);
  }

  return out.toString();
}