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";

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"

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 #)

// .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"

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"

// 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.

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"

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"

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

Static Functions

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

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

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")