
# tecs.io.URI


Immutable absolute URIs for protocols, resources, and application links.

`URI` is not tied to HTTP. It accepts every
absolute scheme supported by the native URL parser, while an API such as the
HTTP client separately restricts the schemes it can use. Components are
parsed once and copied into Lua, so accessors do not reparse or allocate:

```teal
local endpoint <const> = tecs.io.URI.new("https://api.example.com/v1")
local scores <const> = endpoint:concatPath("scores"):withQuery(
    "limit=20"
)

print(scores:scheme(), scores:host(), scores:path())
print(scores)
```

URI values are immutable. Every `with` method and `concatPath` returns a new
value and leaves its receiver unchanged. Supplying a component record to
`tecs.io.URI.new` constructs the complete initial value without intermediate
copies. A modifier clones the retained parsed value and validates only the
replacement component; supplying the existing value returns the receiver.
`withEndpoint` replaces the scheme,
user information, host, and port from another URI, prefixes the receiver's
path with the endpoint path, and preserves the receiver's query and fragment.
That makes a configured service endpoint composable with a modeled resource
URI without rebuilding either from strings.

`resolve` applies an RFC-style relative reference to the receiver. The
constructor itself requires an absolute URI, which keeps every stored value
self-contained and leaves relative text at the operation where its base is
known. A URI owns only immutable Lua strings and needs no `close`.

## Module contents

### Constructors

| Constructor | Description |
| --- | --- |
| [`new`](/modules/io/URI/#tecs.io.URI.new) | Parses and normalizes an absolute URI. |

### Types

| Type | Kind | Description |
| --- | --- | --- |
| [`Components`](/modules/io/URI/#tecs.io.URI.Components) | <span class="tealdoc-kind-badge tealdoc-kind-record">record</span> | Components constructs one URI without intermediate immutable copies. |

### Functions

| Function | Kind | Description |
| --- | --- | --- |
| [`isURI`](/modules/io/URI/#tecs.io.URI.isURI) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Returns whether a value is a Tecs URI. |
| [`validate`](/modules/io/URI/#tecs.io.URI.validate) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Validates an absolute URI without retaining a value. |
| [`authority`](/modules/io/URI/#tecs.io.URI.authority) | <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span> | Returns the encoded authority. |
| [`concatPath`](/modules/io/URI/#tecs.io.URI.concatPath) | <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span> | Appends a path while preserving one separator at the boundary. |
| [`fragment`](/modules/io/URI/#tecs.io.URI.fragment) | <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span> | Returns the encoded fragment without its hash. |
| [`host`](/modules/io/URI/#tecs.io.URI.host) | <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span> | Returns the normalized host. |
| [`password`](/modules/io/URI/#tecs.io.URI.password) | <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span> | Returns the encoded password. |
| [`path`](/modules/io/URI/#tecs.io.URI.path) | <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span> | Returns the encoded path. |
| [`port`](/modules/io/URI/#tecs.io.URI.port) | <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span> | Returns the explicit port. |
| [`query`](/modules/io/URI/#tecs.io.URI.query) | <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span> | Returns the encoded query without its question mark. |
| [`resolve`](/modules/io/URI/#tecs.io.URI.resolve) | <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span> | Resolves a relative or absolute URI reference. |
| [`scheme`](/modules/io/URI/#tecs.io.URI.scheme) | <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span> | Returns the lower-cased scheme without its colon. |
| [`toString`](/modules/io/URI/#tecs.io.URI.toString) | <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span> | Returns the normalized absolute URI. |
| [`userInfo`](/modules/io/URI/#tecs.io.URI.userInfo) | <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span> | Returns the encoded user information. |
| [`username`](/modules/io/URI/#tecs.io.URI.username) | <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span> | Returns the encoded username. |
| [`withEndpoint`](/modules/io/URI/#tecs.io.URI.withEndpoint) | <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span> | Applies another URI as this resource's endpoint. |
| [`withFragment`](/modules/io/URI/#tecs.io.URI.withFragment) | <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span> | Replaces or removes the fragment and returns a new URI. |
| [`withHost`](/modules/io/URI/#tecs.io.URI.withHost) | <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span> | Replaces or removes the host and returns a new URI. |
| [`withPath`](/modules/io/URI/#tecs.io.URI.withPath) | <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span> | Replaces the path and returns a new URI. |
| [`withPort`](/modules/io/URI/#tecs.io.URI.withPort) | <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span> | Replaces or removes the explicit port and returns a new URI. |
| [`withQuery`](/modules/io/URI/#tecs.io.URI.withQuery) | <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span> | Replaces or removes the query and returns a new URI. |
| [`withScheme`](/modules/io/URI/#tecs.io.URI.withScheme) | <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span> | Replaces the scheme and returns a new URI. |
| [`withUserInfo`](/modules/io/URI/#tecs.io.URI.withUserInfo) | <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span> | Replaces or removes user information and returns a new URI. |

## Constructors

<a id="tecs.io.URI.new"></a>
### tecs.io.URI.new <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Parses and normalizes an absolute URI.
A component record performs one construction; it does not allocate an
intermediate URI for each component.


```teal
function tecs.io.URI.new(
    value: string | Components
): URI, string
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `value` | <code>string &#124; </code>[`Components`](/modules/io/URI/#tecs.io.URI.Components) | The caller supplies absolute UTF-8 text or URI components. |

#### Returns

| Type | Description |
| --- | --- |
| [`URI`](/modules/io/URI/) | Returns an immutable URI, or nil when the text is invalid or relative. |
| `string` | Returns the parser's reason when the first return is nil. |

#### Examples

```teal
local endpoint, reason = tecs.io.URI.new(
    "https://user@example.com:8443/assets/list.json?page=2"
)
if endpoint == nil then
    error(reason)
end

assert(endpoint:scheme() == "https")
assert(endpoint:host() == "example.com")
assert(endpoint:port() == 8443)
assert(endpoint:path() == "/assets/list.json")
assert(endpoint:query() == "page=2")
```

## Types

<a id="tecs.io.URI.Components"></a>
### tecs.io.URI.Components <span class="tealdoc-kind-badge tealdoc-kind-record">record</span>

`Components` constructs one URI without intermediate immutable copies.


```teal
record tecs.io.URI.Components
    scheme: string
    userInfo: string
    host: string
    port: integer
    path: string
    query: string
    fragment: string
end
```

#### Examples

```teal
local endpoint, reason = tecs.io.URI.new({
    scheme = "https",
    userInfo = "builder:secret",
    host = "api.example.com",
    port = 8443,
    path = "/v2/scores",
    query = "limit=20",
})
if endpoint == nil then
    error(reason)
end

assert(
    endpoint:toString(
    ) == "https://builder:secret@api.example.com:8443/v2/scores?limit=20"
)
```

<a id="tecs.io.URI.Components.scheme"></a>
#### tecs.io.URI.Components.scheme <span class="tealdoc-kind-badge tealdoc-kind-field">field</span>

Caller-writable. Supplies the required scheme without its colon.


```teal
tecs.io.URI.Components.scheme: string
```

<a id="tecs.io.URI.Components.userInfo"></a>
#### tecs.io.URI.Components.userInfo <span class="tealdoc-kind-badge tealdoc-kind-field">field</span>

Caller-writable. Supplies encoded `username` or
`username:password`, or nil for none.


```teal
tecs.io.URI.Components.userInfo: string
```

<a id="tecs.io.URI.Components.host"></a>
#### tecs.io.URI.Components.host <span class="tealdoc-kind-badge tealdoc-kind-field">field</span>

Caller-writable. Supplies the host, or nil for a scheme without an
authority. IPv6 literals may include or omit brackets.


```teal
tecs.io.URI.Components.host: string
```

<a id="tecs.io.URI.Components.port"></a>
#### tecs.io.URI.Components.port <span class="tealdoc-kind-badge tealdoc-kind-field">field</span>

Caller-writable. Supplies the explicit port, or nil for none.


```teal
tecs.io.URI.Components.port: integer
```

<a id="tecs.io.URI.Components.path"></a>
#### tecs.io.URI.Components.path <span class="tealdoc-kind-badge tealdoc-kind-field">field</span>

Caller-writable. Supplies the path. Nil means an empty path.


```teal
tecs.io.URI.Components.path: string
```

<a id="tecs.io.URI.Components.query"></a>
#### tecs.io.URI.Components.query <span class="tealdoc-kind-badge tealdoc-kind-field">field</span>

Caller-writable. Supplies the query without `?`, or nil for none.


```teal
tecs.io.URI.Components.query: string
```

<a id="tecs.io.URI.Components.fragment"></a>
#### tecs.io.URI.Components.fragment <span class="tealdoc-kind-badge tealdoc-kind-field">field</span>

Caller-writable. Supplies the fragment without `#`, or nil for none.


```teal
tecs.io.URI.Components.fragment: string
```

## Functions

<a id="tecs.io.URI.isURI"></a>
### tecs.io.URI.isURI <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Returns whether a value is a Tecs URI.


```teal
function tecs.io.URI.isURI(value: any): boolean
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `value` | `any` | The caller supplies any Lua value. |

#### Returns

| Type | Description |
| --- | --- |
| `boolean` | Returns true only for values created by this module. |

<a id="tecs.io.URI.validate"></a>
### tecs.io.URI.validate <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Validates an absolute URI without retaining a value.


```teal
function tecs.io.URI.validate(text: string): boolean, string
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `text` | `string` | The caller supplies the UTF-8 text to validate. |

#### Returns

| Type | Description |
| --- | --- |
| `boolean` | Returns true when `new` can parse the text. |
| `string` | Returns the parser's reason when the first return is false. |

#### Examples

```teal
local valid <const> = tecs.io.URI.validate("urn:tecs:asset:sprite")
local relative <const>, reason = tecs.io.URI.validate("../sprite.png")

assert(valid)
assert(not relative)
assert(reason ~= nil)
```

<a id="tecs.io.URI.authority"></a>
### tecs.io.URI:authority <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the encoded authority.


```teal
function tecs.io.URI.authority(self): string
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `URI` | The immutable URI to inspect. |

#### Returns

| Type | Description |
| --- | --- |
| `string` | Returns user information, host, and port, or nil when this URI has no authority. |

<a id="tecs.io.URI.concatPath"></a>
### tecs.io.URI:concatPath <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Appends a path while preserving one separator at the boundary.


```teal
function tecs.io.URI.concatPath(self, path: string): URI
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `URI` | The URI left unchanged. |
| `path` | `string` | The caller supplies the path suffix to append. |

#### Returns

| Type | Description |
| --- | --- |
| [`URI`](/modules/io/URI/) | Returns a new immutable URI. |

#### Examples

```teal
local api, reason = tecs.io.URI.new("https://example.com/v1/")
if api == nil then
    error(reason)
end
local manifest <const> = api:concatPath("/games/42/manifest.json")

assert(manifest:path() == "/v1/games/42/manifest.json")
```

<a id="tecs.io.URI.fragment"></a>
### tecs.io.URI:fragment <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the encoded fragment without its hash.


```teal
function tecs.io.URI.fragment(self): string
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `URI` | The immutable URI to inspect. |

#### Returns

| Type | Description |
| --- | --- |
| `string` | Returns the fragment, or nil when the URI omits it. |

<a id="tecs.io.URI.host"></a>
### tecs.io.URI:host <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the normalized host.


```teal
function tecs.io.URI.host(self): string
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `URI` | The immutable URI to inspect. |

#### Returns

| Type | Description |
| --- | --- |
| `string` | Returns the host, or nil when this scheme has none. |

<a id="tecs.io.URI.password"></a>
### tecs.io.URI:password <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the encoded password.


```teal
function tecs.io.URI.password(self): string
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `URI` | The immutable URI to inspect. |

#### Returns

| Type | Description |
| --- | --- |
| `string` | Returns the password, or nil when none was supplied. |

<a id="tecs.io.URI.path"></a>
### tecs.io.URI:path <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the encoded path.


```teal
function tecs.io.URI.path(self): string
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `URI` | The immutable URI to inspect. |

#### Returns

| Type | Description |
| --- | --- |
| `string` | Returns the path, including its leading slash when present. |

<a id="tecs.io.URI.port"></a>
### tecs.io.URI:port <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the explicit port.


```teal
function tecs.io.URI.port(self): integer
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `URI` | The immutable URI to inspect. |

#### Returns

| Type | Description |
| --- | --- |
| `integer` | Returns the explicit port, or nil when the URI omits it. |

<a id="tecs.io.URI.query"></a>
### tecs.io.URI:query <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the encoded query without its question mark.


```teal
function tecs.io.URI.query(self): string
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `URI` | The immutable URI to inspect. |

#### Returns

| Type | Description |
| --- | --- |
| `string` | Returns the query, or nil when the URI omits it. |

<a id="tecs.io.URI.resolve"></a>
### tecs.io.URI:resolve <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Resolves a relative or absolute URI reference.


```teal
function tecs.io.URI.resolve(self, reference: string): URI, string
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `URI` | The absolute base URI left unchanged. |
| `reference` | `string` | The caller supplies an RFC-style URI reference. |

#### Returns

| Type | Description |
| --- | --- |
| [`URI`](/modules/io/URI/) | Returns the resolved immutable URI. |
| `string` | Returns the parser's reason when the reference is invalid. |

#### Examples

```teal
local page, reason = tecs.io.URI.new(
    "https://example.com/games/current/"
)
if page == nil then
    error(reason)
end
local scores, resolveReason = page:resolve("../42/scores")
if scores == nil then
    error(resolveReason)
end

assert(scores:toString() == "https://example.com/games/42/scores")
```

<a id="tecs.io.URI.scheme"></a>
### tecs.io.URI:scheme <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the lower-cased scheme without its colon.


```teal
function tecs.io.URI.scheme(self): string
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `URI` | The immutable URI to inspect. |

#### Returns

| Type | Description |
| --- | --- |
| `string` | Returns the required scheme. |

<a id="tecs.io.URI.toString"></a>
### tecs.io.URI:toString <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the normalized absolute URI.

`tostring(uri)` returns the same string.


```teal
function tecs.io.URI.toString(self): string
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `URI` | The immutable URI to render. |

#### Returns

| Type | Description |
| --- | --- |
| `string` | Returns the complete normalized URI. |

<a id="tecs.io.URI.userInfo"></a>
### tecs.io.URI:userInfo <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the encoded user information.


```teal
function tecs.io.URI.userInfo(self): string
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `URI` | The immutable URI to inspect. |

#### Returns

| Type | Description |
| --- | --- |
| `string` | Returns `username`, `username:password`, or nil when neither was supplied. |

<a id="tecs.io.URI.username"></a>
### tecs.io.URI:username <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the encoded username.


```teal
function tecs.io.URI.username(self): string
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `URI` | The immutable URI to inspect. |

#### Returns

| Type | Description |
| --- | --- |
| `string` | Returns the username, or an empty string when none was supplied. |

<a id="tecs.io.URI.withEndpoint"></a>
### tecs.io.URI:withEndpoint <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Applies another URI as this resource's endpoint.

The endpoint supplies scheme, user information, host, and port. Its
path prefixes this URI's path; this URI retains its query and fragment.


```teal
function tecs.io.URI.withEndpoint(self, endpoint: URI): URI
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `URI` | The resource URI left unchanged. |
| `endpoint` | [`URI`](/modules/io/URI/) | The caller supplies the service endpoint. |

#### Returns

| Type | Description |
| --- | --- |
| [`URI`](/modules/io/URI/) | Returns a new immutable URI. |

#### Examples

```teal
local resource, resourceReason = tecs.io.URI.new(
    "smithy:/games/42/scores?limit=10"
)
if resource == nil then
    error(resourceReason)
end
local endpoint, endpointReason = tecs.io.URI.new(
    "https://api.example.com/v2"
)
if endpoint == nil then
    error(endpointReason)
end
local request <const> = resource:withEndpoint(endpoint)

assert(
    request:toString(
    ) == "https://api.example.com/v2/games/42/scores?limit=10"
)
```

<a id="tecs.io.URI.withFragment"></a>
### tecs.io.URI:withFragment <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Replaces or removes the fragment and returns a new URI.


```teal
function tecs.io.URI.withFragment(self, fragment: string): URI
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `URI` | The URI left unchanged. |
| `fragment` | `string` | The caller supplies a fragment without `#`, or nil to remove it. |

#### Returns

| Type | Description |
| --- | --- |
| [`URI`](/modules/io/URI/) | Returns a new immutable URI. |

<a id="tecs.io.URI.withHost"></a>
### tecs.io.URI:withHost <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Replaces or removes the host and returns a new URI.


```teal
function tecs.io.URI.withHost(self, host: string): URI
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `URI` | The URI left unchanged. |
| `host` | `string` | The caller supplies a host, or nil when the scheme permits no host. |

#### Returns

| Type | Description |
| --- | --- |
| [`URI`](/modules/io/URI/) | Returns a new immutable URI. |

<a id="tecs.io.URI.withPath"></a>
### tecs.io.URI:withPath <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Replaces the path and returns a new URI.


```teal
function tecs.io.URI.withPath(self, path: string): URI
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `URI` | The URI left unchanged. |
| `path` | `string` | The caller supplies an encoded or unencoded path. |

#### Returns

| Type | Description |
| --- | --- |
| [`URI`](/modules/io/URI/) | Returns a new immutable URI with a normalized path. |

<a id="tecs.io.URI.withPort"></a>
### tecs.io.URI:withPort <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Replaces or removes the explicit port and returns a new URI.


```teal
function tecs.io.URI.withPort(self, port: integer): URI
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `URI` | The URI left unchanged. |
| `port` | `integer` | The caller supplies a port from zero through 65535, or nil to omit it. |

#### Returns

| Type | Description |
| --- | --- |
| [`URI`](/modules/io/URI/) | Returns a new immutable URI. |

<a id="tecs.io.URI.withQuery"></a>
### tecs.io.URI:withQuery <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Replaces or removes the query and returns a new URI.


```teal
function tecs.io.URI.withQuery(self, query: string): URI
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `URI` | The URI left unchanged. |
| `query` | `string` | The caller supplies a query without `?`, or nil to remove it. |

#### Returns

| Type | Description |
| --- | --- |
| [`URI`](/modules/io/URI/) | Returns a new immutable URI. |

#### Examples

```teal
local scores, reason = tecs.io.URI.new("https://example.com/scores")
if scores == nil then
    error(reason)
end
local firstPage <const> = scores:withQuery("limit=20&offset=0")

assert(scores:query() == nil)
assert(firstPage:query() == "limit=20&offset=0")
```

<a id="tecs.io.URI.withScheme"></a>
### tecs.io.URI:withScheme <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Replaces the scheme and returns a new URI.


```teal
function tecs.io.URI.withScheme(self, scheme: string): URI
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `URI` | The URI left unchanged. |
| `scheme` | `string` | The caller supplies a scheme without its colon. |

#### Returns

| Type | Description |
| --- | --- |
| [`URI`](/modules/io/URI/) | Returns a new immutable URI. |

<a id="tecs.io.URI.withUserInfo"></a>
### tecs.io.URI:withUserInfo <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Replaces or removes user information and returns a new URI.


```teal
function tecs.io.URI.withUserInfo(self, userInfo: string): URI
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `URI` | The URI left unchanged. |
| `userInfo` | `string` | The caller supplies `username`, `username:password`, or nil to remove both components. |

#### Returns

| Type | Description |
| --- | --- |
| [`URI`](/modules/io/URI/) | Returns a new immutable URI. |