# normalize static method

String normalize(

1. String url

)

Produces a normalized version of a full URL string by applying various standardizations:

- Converts scheme and host to lowercase
- Removes default ports (80 for HTTP, 443 for HTTPS)
- Resolves path segments (`.` and `..`)
- Reduces multiple slashes
- Removes trailing slashes for non-root paths
- Sorts and re-encodes query parameters
- Re-encodes fragment
- Preserves user info

### Example:

    final url = 'HTTP://Example.com:80/users?id=2&name=John';
    final normalized = UriTemplate.normalize(url);
    print(normalized); // http://example.com/users?id=2&name=John

## Implementation

    static String normalize(String url) {
      Uri uri = Uri.parse(url);

      // Scheme normalization: lowercase
      String normalizedScheme = uri.scheme.toLowerCase();

      // Host normalization: lowercase and remove trailing dot
      String normalizedHost = uri.host.toLowerCase();
      if (normalizedHost.isNotEmpty && normalizedHost.endsWith('.')) {
        normalizedHost = normalizedHost.substring(0, normalizedHost.length - 1);
      }

      // Port normalization: remove default ports
      int? normalizedPort = uri.port;
      if ((normalizedScheme == 'http' && normalizedPort == 80) ||
          (normalizedScheme == 'https' && normalizedPort == 443)) {
        normalizedPort = null; // Indicate default port, so it's not included in the URI string
      }

      // Path normalization: resolve . and .., reduce multiple slashes, remove trailing slash for non-root
      String normalizedPath = uri.path;
      if (normalizedPath.isEmpty) {
        normalizedPath = '/'; // Empty path becomes root path
      } else {
        // Use Uri.parse().normalizePath() to resolve . and .. and handle multiple slashes.
        // This also handles percent-encoding for path segments.
        normalizedPath = normalizePath(normalizedPath);

        // Remove trailing slash if it's not the root path
        if (normalizedPath.length > 1 && normalizedPath.endsWith('/')) {
          normalizedPath = normalizedPath.substring(0, normalizedPath.length - 1);
        }
      }

      // Query normalization: sort parameters by key, then by value, and re-encode
      Map<String, List<String>> queryParams = uri.queryParametersAll;
      List<String> sortedKeys = queryParams.keys.toList()..sort();
      List<String> normalizedQuerySegments = [];

      for (String key in sortedKeys) {
        List<String> values = List.from(queryParams[key]!)..sort(); // Sort values for each key
        String encodedKey = Uri.encodeQueryComponent(key);
        for (String value in values) {
          String encodedValue = Uri.encodeQueryComponent(value);
          normalizedQuerySegments.add('$encodedKey=$encodedValue');
        }
      }
      String? normalizedQuery = normalizedQuerySegments.isEmpty ? null : normalizedQuerySegments.join('&');

      // Fragment normalization: re-encode
      String? normalizedFragment = uri.fragment.isEmpty ? null : Uri.encodeComponent(uri.fragment);

      // Reconstruct the URI
      Uri resultUri = Uri(
        scheme: normalizedScheme,
        userInfo: uri.userInfo.isEmpty ? null : uri.userInfo, // Preserve user info if present
        host: normalizedHost,
        port: normalizedPort,
        path: normalizedPath,
        query: normalizedQuery,
        fragment: normalizedFragment,
      );

      return resultUri.toString();
    }