Fork me on GitHub

URI.js

URI.js API

URI Constructor

var uri = new URI(); // same as new URI(location.href)
// string
var uri = new URI("http://example.org");

// URI object for cloning
var uri = new URI(new URI("http://example.org"));

// URI parts object
var uri = new URI({
    protocol: "http",
    host: "example.org"
});

// without new keyword
var uri = URI("http://example.org");

// resolving right in the constructor
var uri = URI("../foobar.html", "http://example.org/hello/world.html");
// which is exactly the same as 
URI("../foobar.html").absoluteTo("http://example.org/hello/world.html");
// but specified in URL constructor

The following parts can be specified in an object:

var uri = new URI({
    protocol: "http", // no trailing :
    username: "user",
    password: "pass",
    hostname: "example.org",
    port: "80", // string, please
    // "path", not "pathname", sorry
    path: "/foo/bar.html",
    // "query", not "search", sorry
    query: "foo=bar&bar=baz", // no leading ?
    // "fragment", not "hash", sorry
    fragment: "frag" // no leading #
});

using only components of URIs:

// Look ma! I'm only working the pathname
var uri = new URI("some/directory/file.html");

// Look ma! I'm only working the query string
var uri = new URI("?foo=bar");

// Look ma! I'm only working the fragment / hash
var uri = new URI("#call-me-hash");

// and any combination of the above…

cloning URIs

Get a copy of the current URI instance

var uri = new URI("http://example.org"),
    uri2 = uri.clone();

uri2.tld("com");
uri == "http://example.org";
uri2 == "http://example.com";

href()

get and set the entire URI

var uri = URI("http://example.com");
uri.href() === "http://example.com";

uri.href("ftp://google.org");
uri.toString() === "ftp://google.org"

toString(), valueOf()

serialize the URI to string. valueOf() is an alias to toString(), as string is the base primitive.

var uri = URI("http://example.com");
var s = uri.toString();
typeof s === "string";
s === "http://example.com";

protocol(), scheme()

.scheme() is an alias of .protocol()

var uri = new URI("http://example.org/foo/hello.html");
// get protocol
uri.protocol(); // returns string "http"
// set protocol
uri.protocol("ftp"); // returns the URI instance for chaining

// relative scheme
uri.protocol("");
uri.toString() === "//example.org/foo/hello.html";

NOTE: Throws a TypeError on illegal input, that is anything but [a-z0-9.+-] and [empty string] and null

username()

var uri = new URI("http://user:[email protected]/foo/hello.html");
// get username
uri.username(); // returns string "user"
// set username
uri.username("user"); // returns the URI instance for chaining

password()

var uri = new URI("http://user:[email protected]/foo/hello.html");
// get password
uri.password(); // returns string "pass"
// set password
uri.password("user"); // returns the URI instance for chaining

hostname()

var uri = new URI("http://example.org/foo/hello.html");
// get protocol
uri.hostname(); // returns string
// set protocol
uri.hostname("example.org"); // returns the URI instance for chaining

NOTE: .hostname() returns the actual hostname, whereas .host() returns the hostname including the port

port()

var uri = new URI("http://example.org:8080/foo/hello.html");
// get port
uri.port(); // returns string "8080"
// set port
uri.port("80"); // returns the URI instance for chaining

NOTE: although the port may be considered an integer, within URI it is a string.

NOTE: Throws a TypeError on illegal input

host()

var uri = new URI("http://example.org:80/foo/hello.html");
// get host
uri.host(); // returns string "example.org:80"
// set host
uri.host("example.org:80"); // returns the URI instance for chaining

NOTE: .hostname() returns the actual hostname, whereas .host() returns the hostname including the port

userinfo()

Userinfo is comprised of username and password

var uri = new URI("http://user:[email protected]:88/foo/hello.html");
// get userinfo
uri.userinfo(); // returns string "user:pass"
// set userinfo
uri.userinfo("user:pass"); // returns the URI instance for chaining

authority()

Authority is comprised of username, password, hostname and port

var uri = new URI("http://user:[email protected]:88/foo/hello.html");
// get authority
uri.authority(); // returns string "user:[email protected]:88"
// set authority
uri.authority("user:[email protected]:80"); // returns the URI instance for chaining

NOTE: .authority() will reset any of username, password and port if they're not specified.

domain()

.domain() is a convenience method that returns example.org from the hostname www.example.org.

var uri = new URI("http://example.org/foo/hello.html");
// get domain
uri.domain(); // returns string "example.org"
// set domain
uri.domain("otherdomain.com"); // returns the URI instance for chaining

// Second Level Domain (SLD) Support (as of URI.js 1.5.0)
uri = new URI("http://example.co.uk/foo/hello.html");
uri.domain(); // return string "example.co.uk"
uri.domain(true); // return string "co.uk"

NOTE: .domain() will throw an error if you pass it an empty string.

NOTE: Throws a TypeError on illegal input

subdomain()

.subdomain() is a convenience method that returns www from the hostname www.example.org.

var uri = new URI("http://www.example.org/foo/hello.html");
// get subdomain
uri.subdomain(); // returns string "www"
// set subdomain
uri.subdomain("other.subdomain"); // returns the URI instance for chaining

NOTE: Throws a TypeError on illegal input

tld()

.tld() is a convenience method that returns org from the hostname www.example.org.

var uri = new URI("http://example.org/foo/hello.html");
// get tld
uri.tld(); // returns string "org"
// set tld
uri.tld("com"); // returns the URI instance for chaining

// Second Level Domain (SLD) Support (as of URI.js 1.5.0)
uri = new URI("http://example.co.uk/foo/hello.html");
uri.tld(); // return string "co.uk"
uri.tld(true); // return string "uk"

NOTE: Throws an Error if you pass it an empty string or use it on an IP-host.

pathname(), path()

.path() is an alias of .pathname()

var uri = new URI("http://example.org/foo/hello.html");
// get pathname
uri.pathname(); // returns string "/foo/hello.html"
// set pathname
uri.pathname("/foo/hello.html"); // returns the URI instance for chaining

// will encode for you
uri.pathname("/hello world/");
uri.pathname() === "/hello%20world/";
// will decode for you
uri.pathname(true) === "/hello world/";

directory()

.directory() is an convenience method for mutating the directory part of a path

var uri = new URI("http://example.org/foo/hello.html");
// get directory
uri.directory(); // returns string "/foo" (no trailing slash)
// set directory
uri.directory("/bar"); // returns the URI instance for chaining
// uri == "http://example.org/bar/hello.html"

// will encode for you
uri.directory("/hello world/");
uri.directory() === "/hello%20world";
// will decode for you
uri.directory(true) === "/hello world";

uri.href("http://example.com/foo").directory()
// -&t; "/"
uri.href("/foo").directory()
// -&t; "/"
uri.href("foo").directory()
// -&t; ""

filename()

.filename() is an convenience method for mutating the filename part of a path

var uri = new URI("http://example.org/foo/hello.html");
// get filename
uri.filename(); // returns string "hello.html" (no leading slash)
// set filename
uri.filename("world.xml"); // returns the URI instance for chaining
// uri == "http://example.org/bar/world.xml"

// will encode for you
uri.filename("hello world.html");
uri.filename() === "hello%20world.html";
// will decode for you
uri.filename(true) === "hello world.html";

NOTE: If you pass ../file.html, the directory will be changed accordingly

suffix()

.suffix() is an convenience method for mutating the filename part of a path

var uri = new URI("http://example.org/foo/hello.html");
// get suffix
uri.suffix(); // returns string "html" (no leading dot)
// set suffix
uri.suffix("xml"); // returns the URI instance for chaining
// uri == "http://example.org/bar/world.xml"

// will encode for you
uri.suffix("würgh");
uri.suffix() === "w%C3%BCrgh";
// will decode for you
uri.suffix(true) === "würgh";

segment()

.segment() allows convenient access to directory levels / URN segments within the path

var uri = new URI("http://example.org/foo/hello.html");
// get segments
uri.segment(); // returns array ["foo", "hello.html"]
// set segments
uri.segment(["foo", "bar", "foobar.html"]); // -> http://example.org/foo/bar/foobar.html

// get specific level
uri.segment(0); // returns "foo"
uri.segment(1); // returns "bar"
uri.segment(-1); // returns "foobar.html"
// set specific level
uri.segment(0, "bar"); // -> http://example.org/bar/bar/foobar.html
// remove specific level
uri.segment(0, ""); // -> http://example.org/bar/foobar.html


// append level
uri.segment("appendthis"); // -> http://example.org/bar/foobar.html/appendthis
var uri = new URI("http://example.org/foo/hello.html?foo=bar&bar=baz");
// get search
uri.search(); // returns string "?foo=bar&bar=baz" (leading ?)
// get query
uri.query(); // returns string "foo=bar&bar=baz" (no leading ?)

// .query() and .search() behave the same for the following:

// set search
uri.search("?foo=bar&bar=baz"); // returns the URI instance for chaining
uri.search("foo=bar&bar=baz"); // returns the URI instance for chaining
// uri == "http://example.org/bar/world.html?foo=bar&bar=baz"

// remove query
uri.search(""); // returns the URI instance for chaining
// uri == "http://example.org/bar/world.html"

// get data map:
uri.search(true); // returns { foo: "bar", hello : ["world", "mars"] }

// set data map:
uri.search({ foo: "bar", hello : ["world", "mars"] });
// uri == "http://example.org/bar/world.html?foo=bar&hello=world&hello=mars"

// CAUTION: beware of arrays, the following are not quite the same
// If you're dealing with PHP, you probably want the latter…
uri.search("?foo=bar&bar=baz");
uri.search("?foo=bar[]&bar[]=baz");

Note that names and values passed in an object are encoded automatically. The object, resulting from parsing the query string, contains decoded values

Hint: If you're using jQuery, have a look at their .serialize() function.

hash(), fragment()

var uri = new URI("http://example.org/foo/hello.html#world");
// get hash
uri.hash(); // returns string "#world" (leading #)
// get fragment
uri.fragment(); // returns string "world" (no leading #)

// remove fragment
uri.fragment(""); // returns the URI instance for chaining
// uri == "http://example.org/bar/world.html"

// .hash() and .fragment() behave the same for the following:

// set hash
uri.hash("#mars"); // returns the URI instance for chaining
uri.hash("mars"); // returns the URI instance for chaining
// uri == "http://example.org/bar/world.xml#mars"

resource()

Resource is comprised of path, query and fragment

var uri = new URI("http://example.org/foo/hello.html?query=string#hash");
// get resource
uri.resource(); // returns string "/foo/hello.html?query=string#hash"
// set resource
uri.resource("/mars.txt?query=foo#other"); // returns the URI instance for chaining

NOTE: .resource() will reset any of path, query and fragment if they're not specified.

is()

.is() tells what a URL is. It responds with a boolean and can be asked the following questions:

relative
true if URL doesn't have a hostname
absolute
true if URL has a hostname
urn
true if URI is a URN
url
true if URI is a URL
domain, name
true if hostname is not an IP
sld
true if hostname is a second level domain (i.e. "example.co.uk")
idn
true if hostname contains non-alphanumeric characters and is not an IP
punycode
true if hostname contains xn--
ip
true if hostname is IPv4 or IPv6
ip4, ipv4, inet4
true if hostname is IPv4
ip6, ipv6, inet6
true if hostname is IPv6
var uri = new URI("http://example.org/");
uri.is("relative") === false;
uri.is("absolute") === true;
uri.is("urn") === false;
uri.is("url") === true;
uri.is("name") === true;
uri.is("sld") === false;
uri.is("punycode") === false;
uri.is("IDN") === false; // case doesn't matter
uri.is("idn") === false; // case doesn't matter
uri.is("ip") === false;

var uri = new URI("http://123.123.123.123/");
uri.is("relative") === false;
uri.is("absolute") === true;
uri.is("urn") === false;
uri.is("url") === true;
uri.is("name") === false;
uri.is("sld") === false;
uri.is("IP") === true;
uri.is("IPv4") === true;
uri.is("IPv6") === false;

var uri = new URI("http://fe80:0000:0000:0000:0204:61ff:fe9d:f156/");
uri.is("IP") === true;
uri.is("IPv4") === false;
uri.is("IPv6") === true;

var uri = new URI("/hello/world.html");
uri.is("relative") === true;
uri.is("absolute") === false;
uri.is("urn") === false;
uri.is("url") === true;
uri.is("name") === false;
uri.is("IP") === false;

var uri = new URI("http://example.co.uk/");
uri.is("name") === true;
uri.is("sld") === true;

var uri = new URI("mailto:[email protected]");
uri.is("relative") === false;
uri.is("absolute") === false;
uri.is("urn") === true;
uri.is("url") === false;
uri.is("name") === false;
uri.is("sld") === false;
uri.is("punycode") === false;
uri.is("idn") === false;
uri.is("ip") === false;

Working with the query string

addSearch(), addQuery()

.addQuery() is an alias of .addSearch()

var uri = new URI("?hello=world");
uri.addSearch("hello", "mars"); // returns the URI instance for chaining
// uri == "?hello=world&hello=mars"

uri.addSearch({ foo: "bar", goodbye : ["world", "mars"] });
// uri == "?hello=world&hello=mars&foo=bar&goodbye=world&goodbye=mars"

uri.addSearch("no-value");
// uri == "?hello=world&hello=mars&foo=bar&goodbye=world&goodbye=mars&no-value"

// CAUTION: beware of arrays, the following are not quite the same
// If you're dealing with PHP, you probably want the latter…
uri.addSearch("foo", ["bar", "baz"]);
uri.addSearch("foo[]", ["bar", "baz"]);

Note that names and values passed in are encoded automatically.

removeSearch(), removeQuery()

.removeQuery() is an alias of .removeSearch()

var uri = new URI("?hello=world&hello=mars&foo=bar");
// remove an attribute
uri.removeSearch("hello"); // returns the URI instance for chaining
// uri == "?foo=bar"

// remove an attribute with value filter
uri.search("?hello=world&hello=mars&foo=bar");
uri.removeSearch("hello", "world"); // returns the URI instance for chaining
// uri == "?hello=mars&foo=bar"

// remove multiple values
uri.search("?hello=world&hello=mars&foo=bar&mine=true");
uri.removeSearch(["hello", "foo"]);
// uri == "?mine=true" 

// remove multiple values with value filter
uri.search("?hello=world&hello=mars&foo=bar&mine=true&a=1&a=2&a=3");
uri.removeSearch({hello: "world", foo: undefined, a: ["1", "3"]});
// uri == "?hello=mars&mine=true&a=2"

Working with the Fragment (Hash)

There are virtually no limits to what you might do with fragments (hash). Every system has their own bag of tricks. As a result URI.js cannot offer any of the following tools right out of the box. The most common abuse of fragments are storing URLs or query string like data.

Usually a prefix is used to identify data with special meaning. This prefix can be pretty much what you want. For URIs it's usually ! and for query-like data it often is ?. But they don't have to, which is why you can define a global default: URI.fragmentPrefix = "$";

Query String Fragments

The file src/URI.fragmentQuery.js is a "plugin" that allows you to store data in hashes in the same manner the .query() functions provide.

var uri = new URI("#?hello=world");
uri.addFragment("hello", "mars"); // returns the URI instance for chaining
// uri == "#?hello=world&hello=mars"

// to change the fragment prefix on an instance level:
uri.fragmentPrefix("!"); 

// to change the fragment prefix on a global level:
URI.fragmentPrefix = "!";

URL Fragments

The file src/URI.fragmentURI.js is a "plugin" that allows you to store URLs in hashes.

var uri = URI("http://example.org/#!/foo/bar/baz.html"),
    furi = uri.fragment(true);

// manipulating the fragment URI
furi.pathname() === "/foo/bar/baz.html";
furi.pathname("/hello.html");

// has direct effect on the actual URI
uri.toString() === "http://example.org/#!/hello.html"

// to change the fragment prefix on an instance level:
uri.fragmentPrefix("?"); 

// to change the fragment prefix on a global level:
URI.fragmentPrefix = "?";

Normalizing URLs

normalize()

executes normalizeProtocol(), normalizeHostname(), normalizePort(), normalizePath(), normalizeSearch(), normalizeHash()

normalizeProtocol()

var uri = new URI("hTTp://www.example.org/");
// normalize protocol
uri.normalizeProtocol(); // returns the URI instance for chaining
// uri == "http://www.example.org/"

normalizeHostname()

For IDN conversion punycode.js must be available (bundled in URI.js). For IPv6-best-notation conversion IPv6.js must be available (bundled in URI.js). Also lower-cases hostnames.

var uri = new URI("http://www.exämple.org/");
// normalize IDN host
uri.normalizeHostname(); // returns the URI instance for chaining
// uri == "http://www.xn--exmple-cua.org/"

// normalize IPv6 host
uri.hostname("fe80:0000:0000:0000:0204:61ff:fe9d:f156");
uri.normalizeHostname(); // returns the URI instance for chaining
// uri == "http://fe80::204:61ff:fe9d:f156/"

// normalize hostname to lower case
uri.hostname("wWw.eXample.Org");
uri.normalizeHostname(); // returns the URI instance for chaining
// uri == "http://www.example.org/"

There is no .normalizeHost(), as .host() is a property comprised of .hostname() and .port()

normalizePort()

Removes the port, if it's the default for the given protocol (http: 80, https: 443, ftp: 21).

The list of default ports can be modified at URI.defaultPorts

var uri = new URI("http://example.org:80/foo.html");
// normalize port
uri.normalizePort(); // returns the URI instance for chaining
// uri == "http://example.org/foo.html"

normalizePathname(), normalizePath()

.normalizePath() is an alias of .normalizePathname(), they resolve relative hierarchies

var uri = new URI("/hello/foo/woo/.././../world.html");
// normalize path
uri.normalizePathname(); // returns the URI instance for chaining
// uri == "/hello/world.html"

Turns ?&foo=bar&&foo=bar&foo=baz& into ?foo=bar&foo=baz and removes ? if there is no query string.

var uri = new URI("?&foo=bar&&foo=bar&foo=baz&");
// normalize search
uri.normalizeSearch(); // returns the URI instance for chaining
// uri == "?foo=bar&foo=baz"

normalizeHash(), normalizeFragment()

removes # if there is no hash

var uri = new URI("http://example.org/foo/hello.html#");
// normalize hash
uri.normalizeHash(); // returns the URI instance for chaining
// uri == "http://example.org/bar/world.xml"

Charsets / Encodings

iso8859()

.iso8859() converts unicode-encoded escape sequences to ISO8859-encoded escape sequences. It does this by calling .normalize() internally.

var uri = new URI("/%C3%A4.html");
uri.iso8859(); // returns the URI instance for chaining
// uri == "/%E4.html"

NOTE: You can make URI work with ISO8859 encoding by default by calling URI.iso8859().

unicode()

.unicode() converts ISO8859-encoded escape sequences to unicode-encoded escape sequences. It does this by calling .normalize() internally.

var uri = new URI("/%E4.html");
uri.unicode(); // returns the URI instance for chaining
// uri == "/%C3%A4.html"

Formatting URLs

readable()

Formats URLs to be human readable (much like your browser does nowadays).

var uri = new URI("http://foo:[email protected]/"
    + "hello%20world/ä.html?foo%5B%5D=b+är#fragment");

u.readable() === "http://www.exämple.org/"
    + "hello world/ä.html?foo[]=b är#fragment";

Relative and Absolute URLs

relativeTo()

.relativeTo() compares two paths an makes one relative to the other

var uri = new URI("/relative/path");
// make path relative
var relUri = uri.relativeTo("/relative/sub/foo/sub/file"); // returns a new URI instance
// relUri == "../../../path"

// also works for relative directories
URI("../world.html").absoluteTo("foo/bar/baz.html");
// -> "foo/world.html"

// absolute URLs are passed through unchanged
URI("http://example.org/world.html").absoluteTo("http://google.com/baz");
// -> "http://example.org/world.html"

// absolute URLs relative to absolute URLs
URI("http://example.org/world.html").clone().authority("").absoluteTo("http://google.com/baz");
// -> "http://google.com/world.html"

.relativeTo() and .absoluteTo() reverse each other.

absoluteTo()

.absoluteTo() makes a relative path absolute based on another path

var uri = new URI("../../../path");
// make path absolute
var relUri = uri.absoluteTo("/relative/sub/foo/sub/file"); // returns a new URI instance
// relUri == "/relative/path"

.relativeTo() and .absoluteTo() reverse each other.

Comparing URLs

equals()

.equals() determines if the given URLs are the same - disregarding default ports, capitalization, dot-pathnames, query-parameter order, etc.

var a = "http://example.org/foo/bar.html"
        + "?foo=bar&hello=world&hello=mars#fragment",
    b;

// normalizing URI before comparison:
b = "http://exAMPle.org:80/foo/../foo/bar.html"
    + "?foo=bar&hello=world&hello=mars#fragment";

a !== b;
URI(a).equals(b) === true;


// comparing query string parameters:
b = "http://example.org/foo/bar.html"
    + "?hello=mars&foo=bar&hello=world&#fragment";

a !== b;
URI(a).equals(b) === true;

// shorthand for comparing to window.location.href:
URI(a).equals();

Parsing URLs

URI.parse(string url)

parses a string into its URI components. returns an object containing the found components

var result = URI.parse("http://example.org/foo.html");
result === {
    protocol: "http", 
    username: null, 
    password: null, 
    hostname: "example.org",
    port: null,
    path: "/foo.html",
    query: null,
    fragment: null
};

URI.parseAuthority(string url, object parts)

parses a string's beginning into its URI components username, password, hostname, port. Found components are appended to the parts parameter. Remaining string is returned

var parts = {},
    result = URI.parseAuthority("user:[email protected]:8080/foo.html", parts);
result === "/foo.html";
parts === {
    username: "user", 
    password: "pass", 
    hostname: "example.org",
    port: "8080"
};

URI.parseUserinfo(string url, object parts)

parses a string's beginning into its URI components username, password. Found components are appended to the parts parameter. Remaining string is returned

var parts = {},
    result = URI.parseUserinfo("user:[email protected]:8080/foo.html", parts);
result === "example.org:8080/foo.html";
parts === {
    username: "user", 
    password: "pass"
};

URI.parseHost(string url, object parts)

parses a string's beginning into its URI components hostname, port. Found components are appended to the parts parameter. Remaining string is returned

var parts = {},
    result = URI.parseAuthority("example.org:8080/foo.html", parts);
result === "/foo.html";
parts === {
    hostname: "example.org",
    port: "8080"
};

URI.parseQuery(string querystring)

Parses the passed query string into an object. Returns object {propertyName: propertyValue}

var result = URI.parseQuery("?foo=bar&hello=world&hello=mars&bam=&yup");
result === {
    foo: "bar",
    hello: ["world", "mars"],
    bam: "",
    yup: null
};

Serializing URLs

URI.build(object parts)

serializes the URI components passed in parts into a URI string

var parts = {
    protocol: "http", 
    username: null, 
    password: null, 
    hostname: "example.org",
    port: null,
    path: "/foo.html",
    query: null,
    fragment: null
};
URI.build(parts) === "http://example.org/foo.html";

URI.buildAuthority(object parts)

serializes the URI components username, password, hostname, port passed in parts into a URI string

var parts = {
    username: "user", 
    password: "pass", 
    hostname: "example.org",
    port: "8080"
};
URI.buildAuthority(parts) === "user:[email protected]:8080";

URI.buildUserinfo(object parts)

serializes the URI components username, password passed in parts into a URI string

var parts = {
    username: "user", 
    password: "pass"
};
URI.buildUserinfo(parts) === "user:pass@";

URI.buildHost(object parts)

serializes the URI components hostname, port passed in parts into a URI string

var parts = {
    hostname: "example.org",
    port: "8080"
};
URI.buildHost(parts) === "example.org:8080";

URI.buildQuery(object data, [boolean duplicates])

serializes the query string parameters

var data = {
    foo: "bar",
    hello: ["world", "mars", "mars"],
    bam: "",
    yup: null,
    removed: undefined
}

// Note: duplicate hello=mars is dropped (default behavior!)
URI.buildQuery(data) === "foo=bar&hello=world&hello=mars&bam=&yup";

// Note: duplicate hello=mars is preserved
URI.buildQuery(data, true) === "foo=bar&hello=world&hello=mars&hello=mars&bam=&yup";

To preserve duplicate values, use URI.buildQuery() directly:

var uri = new URI("http://example.org/foo.html?bar=baz"),
    data = uri.query(true);

data.some = "new data";
uri.query(URI.buildQuery(data, true));

// you can also use the static URI.addQuery() and URI.removeQuery()
URI.addQuery(data, "hello", "world");
uri.query(URI.buildQuery(data, true));

As of v1.8.0 you can configure query parameter de/duplication:

// make all new URI instances allow duplicates:
URI.duplicateQueryParameters = true; // default is false

// make a specific URI instance allow duplicates:
var withDuplicates = URI("?bar=1&bar=1")
  .duplicateQueryParameters(true)
  .normalizeQuery()
  .toString();

// make a specific URI instance avoid duplicates (default):
var noDuplicates = URI("?bar=1&bar=1")
  .duplicateQueryParameters(false)
  .normalizeQuery()
  .toString();

withDuplicates === "?bar=1&bar=1";
noDuplicates === "?bar=1";

Encoding and Decoding URLs

URI.encode()

Encode an URI component with strict compliance to RFC3986

URI.encode("hä lo#w*rl:d!") === "h%C3%A4%20lo%23w%2Arl%3Ad%21";
// vs.
encodeURIComponent("hä lo#w*rl:d!") === "h%C3%A4%20lo%23w*rl%3Ad!";
// not how * and ! were not encoded

URI.decode()

Decode an URI component

URI.encode("h%C3%A4%20lo%23w%2Arl%3Ad%21") === "hä lo#w*rl:d!";
// note:
URI.decode === decodeURIComponent;

URI.encodeReserved()

Encode an URI component whilst preserving reserved characters

URI.encodeReserved("ä:/?#[]@!$&'()*+,;=") === "%C3%A4:/?#[]@!$&'()*+,;=";
// vs.
URI.encode("ä:/?#[]@!$&'()*+,;=") === 
  "%C3%A4%3A%2F%3F%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D";

URI.encodeQuery()

Decode a query string component. Works like encode(), except it handles %20 as + (space).

URI.encodeQuery(" ") === "+";
// vs.
URI.encode(" ") === "%20";

URI.decodeQuery()

Decode a query string component. Works like decode(), except it handles + as %20 (space).

URI.decodeQuery("+") === " ";
// vs.
URI.decode("+") === "+";

Static Helper Functions

URI.addQuery()

adds data to a map

var data = {};

URI.addQuery(data, "hello", "mars");
data === {hello: "mars"};

URI.addQuery(data, "hello", "world");
data === {hello: ["mars", "world"]};

URI.addQuery(data, {foo: "bar", goodbye : ["world", "mars"]});
data === {hello: ["mars", "world"], foo: "bar", goodbye : ["world", "mars"]};

URI.removeQuery()

removes data from a map

var data === {hello: ["mars", "world"], foo: "bar", goodbye : ["world", "mars"]};

URI.removeQuery(data, "hello");
data === {foo: "bar", goodbye : ["world", "mars"]};

// remove an attribute with value filter
data = {hello: ["world", "mars"], foo: "bar"};
URI.removeQuery(data, "hello", "world");
data === {hello: ["mars"], foo: "bar"} // yes, still an array

// remove multiple values
data = {hello: ["world", "mars"], foo: "bar", mine: "true"}
URI.removeQuery(["hello", "foo"]);
data === {mine: "true"};

// remove multiple values with value filter
data = {hello: ["world", "mars"], foo: "bar", mine: "true", a: ["1", "2", "3"]}
URI.removeQuery({hello: "world", foo: undefined, a: ["1", "3"]});
data === {hello: ["mars"], mine: "true", a: ["2"]}

URI.commonPath()

URI.commonPath() determines the common base directory of two paths.

URI.commonPath("/foo/bar/baz.html", "/foo/bar/world.html");
// returns "/foo/bar/"

URI.commonPath("/foo/bar/baz.html", "/foo/bazz/world.html");
// returns "/foo/"

URI.commonPath("/foo/bar/baz.html", "/other/world.html");
// returns "/"

URI.commonPath("/foo", "bar");
// returns ""

URI.withinString()

URI.withinString() identifies URIs within text, e.g. to translate them to <a>-Tags. (Obviously you'd want to put the urls inside the href-Attribute and escape them properly…)

var source = "Hello www.example.com,\n"
    + "http://google.com is a search engine, like http://www.bing.com\n"
    + "http://exämple.org/foo.html?baz=la#bumm is an IDN URL,\n"
    + "http://123.123.123.123/foo.html is IPv4 and "
    + "http://fe80:0000:0000:0000:0204:61ff:fe9d:f156/foobar.html is IPv6.\n"
    + "links can also be in parens (http://example.org) "
    + "or quotes »http://example.org«.";

var result = URI.withinString(source, function(url) {
    // callback needs to return a string
    // feel free to URI(url).normalize().toString() or something
    return "<a>" + url + "</a>";
});

/* result is:
Hello <a>www.example.com</a>,
<a>http://google.com</a> is a search engine, like <a>http://www.bing.com</a>
<a>http://exämple.org/foo.html?baz=la#bumm</a> is an IDN URL,
<a>http://123.123.123.123/foo.html</a> is IPv4 and <a>http://fe80:0000:0000:0000:0204:61ff:fe9d:f156/foobar.html</a> is IPv6.
links can also be in parens (<a>http://example.org</a>) or quotes »<a>http://example.org</a>«.
*/

// a proper replacement could look like the following:
var escapeHtml = function(string) { 
        return string
            .replace(/&/g, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;")
            .replace(/"/g, "&quot;");
    }
    result = URI.withinString(source, function(url) {
        var uri = new URI(url);
        uri.normalize();
        return "<a href="" + escapeHtml(uri) + "">" 
            + escapeHtml(url.readable()) + "</a>";
    });

URI.iso8859()

URI.iso8859() tells URI.js to use the older escape/unescape methods, for backwards compatibility with non-unicode platforms.

URI.iso8859();

var uri = new URI("http://example.org/foo/æ.html");
// http://example.org/foo/%E6.html

URI.unicode()

URI.unicode() restores the default unicode-encoded URLs.

URI.unicode();

var uri = new URI("http://example.org/foo/æ.html");
// http://example.org/foo/%C3%A6.html

URI.expand()

URI.expand() is a convenience wrapper for URITemplate. While URITemplate#expand returns a string, URI.expand() returns an URI instance.

URI.expand("/foo/{var}/{iable}", {
  "var": "bar",
  "iable": "hello world.html"
});

// returns URI("/foo/bar/hello%20world.html")