<commit_before>package thx;

import thx.Error;
using thx.Strings;

/**
It's a type that represents a URL.
*/
abstract Url(UrlType) from UrlType to UrlType {
  static var pattern = ~/^((((?:([^:\/#\?]+):)?(?:(\/\/)?((?:(([^:@\/#\?]+)(?:[:]([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:[:]([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(?:\?([^#]+))?)(?:#(.*))?/;
/**
Generates a URL instance from a `String`. It throws an exception if the string
cannot be parsed to a valid URL.

The URL can be either relative or absolute.
*/
  @:from public static function parse(s : String) : Url {
    if(!pattern.match(s)) throw new Error('unable to parse "$s" to Url');
    var port = pattern.matched(12),
        o : Url = {
          protocol : pattern.matched(4),
          slashes: pattern.matched(5) == "//",
          auth: pattern.matched(7),
          hostName: pattern.matched(11),
          port: null == port ? null : Std.parseInt(port),
          pathName: pattern.matched(13),
          queryString: null,
          search: null,
          hash: pattern.matched(17)
        };
    o.search = pattern.matched(16);
    return o;
  }

  public var auth(get, set) : String;
  public var hash(get, set) : String;
  public var hasAuth(get, never) : Bool;
  public var hasHash(get, never) : Bool;
  public var hasPort(get, never) : Bool;
  public var hasProtocol(get, never) : Bool;
  public var hasQueryString(get, never) : Bool;
  public var hasSearch(get, never) : Bool;
  public var host(get, set) : String;
  public var hostName(get, set) : String;
  public var href(get, set) : String;
  public var isAbsolute(get, never) : Bool;
  public var isRelative(get, never) : Bool;
  public var path(get, set) : String;
  public var pathName(get, set) : String;
  public var port(get, set) : Null<Int>;
  public var protocol(get, set) : String;
  public var queryString(get, set) : QueryString;
  public var search(get, set) : String;
  public var slashes(get, set) : Bool;

/**
Matches all the URL parts with another URL and returns true if they are all
equals.
*/
  @:op(A == B) public function equals(other : Url) : Bool
    return
      this.protocol == other.protocol &&
      this.slashes == other.slashes &&
      this.auth == other.auth &&
      this.hostName == other.hostName &&
      this.port == other.port &&
      this.pathName == other.pathName &&
      this.queryString.equals(other.queryString) &&
      this.search == other.search &&
      this.hash == other.hash;

  @:op(A / B) public function concatString(other : String) : Url {
    var copy = clone();
    if(pathName.isEmpty()) {
      if(!other.startsWith("/"))
        other = "/" + other;
      copy.pathName = other;
    } else {
      if(other.startsWith("/"))
        other = other.substring(1);
      if(pathName.endsWith("/"))
        copy.pathName = copy.pathName + other;
      else
        copy.pathName = copy.pathName + "/" + other;
    }
    return copy;
  }

  @:to public function toString()
    return if(isAbsolute)
      '${hasProtocol ? protocol + ":" : ""}${slashes?"//":""}${hasAuth?auth+"@":""}$host$path${hasHash?"#"+hash:""}';
    else
      '$path${hasHash?"#"+hash:""}';

  public function clone() : Url {
    return {
      protocol: protocol,
      slashes: slashes,
      auth: auth,
      hostName: hostName,
      port: port,
      pathName: pathName,
      queryString: queryString,
      search: search,<commit_msg>updated Url to use static function for equality<commit_after>package thx;

import thx.Error;
using thx.Strings;

/**
It's a type that represents a URL.
*/
abstract Url(UrlType) from UrlType to UrlType {
  static var pattern = ~/^((((?:([^:\/#\?]+):)?(?:(\/\/)?((?:(([^:@\/#\?]+)(?:[:]([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:[:]([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(?:\?([^#]+))?)(?:#(.*))?/;
/**
Generates a URL instance from a `String`. It throws an exception if the string
cannot be parsed to a valid URL.

The URL can be either relative or absolute.
*/
  @:from public static function parse(s : String) : Url {
    if(!pattern.match(s)) throw new Error('unable to parse "$s" to Url');
    var port = pattern.matched(12),
        o : Url = {
          protocol : pattern.matched(4),
          slashes: pattern.matched(5) == "//",
          auth: pattern.matched(7),
          hostName: pattern.matched(11),
          port: null == port ? null : Std.parseInt(port),
          pathName: pattern.matched(13),
          queryString: null,
          search: null,
          hash: pattern.matched(17)
        };
    o.search = pattern.matched(16);
    return o;
  }

  public var auth(get, set) : String;
  public var hash(get, set) : String;
  public var hasAuth(get, never) : Bool;
  public var hasHash(get, never) : Bool;
  public var hasPort(get, never) : Bool;
  public var hasProtocol(get, never) : Bool;
  public var hasQueryString(get, never) : Bool;
  public var hasSearch(get, never) : Bool;
  public var host(get, set) : String;
  public var hostName(get, set) : String;
  public var href(get, set) : String;
  public var isAbsolute(get, never) : Bool;
  public var isRelative(get, never) : Bool;
  public var path(get, set) : String;
  public var pathName(get, set) : String;
  public var port(get, set) : Null<Int>;
  public var protocol(get, set) : String;
  public var queryString(get, set) : QueryString;
  public var search(get, set) : String;
  public var slashes(get, set) : Bool;

/**
Matches all the URL parts with anthat URL and returns true if they are all
equals.
*/
  @:op(A==B)
  public static function equals(self : Url, that : Url) : Bool
    return self.equalsTo(that);

  public function equalsTo(that : Url) : Bool
    return
      this.protocol == that.protocol &&
      this.slashes == that.slashes &&
      this.auth == that.auth &&
      this.hostName == that.hostName &&
      this.port == that.port &&
      this.pathName == that.pathName &&
      this.queryString.equals(that.queryString) &&
      this.search == that.search &&
      this.hash == that.hash;

  @:op(A/B)
  public function concatString(that : String) : Url {
    var copy = clone();
    if(pathName.isEmpty()) {
      if(!that.startsWith("/"))
        that = "/" + that;
      copy.pathName = that;
    } else {
      if(that.startsWith("/"))
        that = that.substring(1);
      if(pathName.endsWith("/"))
        copy.pathName = copy.pathName + that;
      else
        copy.pathName = copy.pathName + "/" + that;
    }
    return copy;
  }

  @:to public function toString()
    return if(isAbsolute)
      '${hasProtocol ? protocol + ":" : ""}${slashes?"//":""}${hasAuth?auth+"@":""}$host$path${hasHash?"#"+hash:""}';
    else
      '$path${hasHash?"#"+hash:""}';

  public function clone() : Url {
    return {
      protocol: protocol,
      slashes: slashes,
      auth: auth,
      hostName: hostName,
      port: port,
      pathName: pathName,
      queryString: queryString,
      search: search,
{'fraction_non_alphanumeric': 0.18797531927105754, 'fraction_numerical': 0.004591763524178505, 'mean_word_length': 2.8614958448753463, 'pattern_counts': {'":': 6, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '602442', 'n_tokens_mistral': 2372, 'n_tokens_neox': 2311, 'n_words': 618}