convert a url string to an actual URL object. your input path url can use any scheme supported by the getUriScheme function. and you may also use paths with windows dir-separators ("\"), as this function implicitly converts them a posix separator ("/").

if you pass a URL object, then it will be returned as is.

Error an error will be thrown if base uri is either a relative path, or uses a data uri scheme, or if the provided path is relative, but no absolute base path is provided.

import { assertEquals, assertThrows } from "jsr:@std/assert"

// aliasing our functions for brevity
const eq = assertEquals, err = assertThrows, fn = resolveAsUrl

eq(fn(new URL("some://url:8000/a/b c.txt")), new URL("some://url:8000/a/b%20c.txt"))

eq(fn("/a/b/c d e.txt"), new URL("file:///a/b/c%20d%20e.txt"))
eq(fn("~/a/b/c.txt"), new URL("file://~/a/b/c.txt"))
eq(fn("C:/a/b/c/d/e.txt"), new URL("file:///C:/a/b/c/d/e.txt"))
eq(fn("C:\\a\\b\\c\\d\\e.txt"), new URL("file:///C:/a/b/c/d/e.txt"))
eq(fn("./e/f g.txt", "C:/a\\b\\c d/"), new URL("file:///C:/a/b/c%20d/e/f%20g.txt"))
eq(fn("../c d/e/f g.txt", "C:/a/b/c d/"), new URL("file:///C:/a/b/c%20d/e/f%20g.txt"))

eq(fn("http://cdn.esm.sh/a/b/c.txt"), new URL("http://cdn.esm.sh/a/b/c.txt"))
eq(fn("http://cdn.esm.sh/a.txt", "file:///b/"), new URL("http://cdn.esm.sh/a.txt"))
eq(fn("http://cdn.esm.sh/a.txt", "/b/"), new URL("http://cdn.esm.sh/a.txt"))
eq(fn("/a/b/c.txt", "http://cdn.esm.sh/"), new URL("file:///a/b/c.txt"))

eq(fn("b/c.txt", "http://cdn.esm.sh/a/"), new URL("http://cdn.esm.sh/a/b/c.txt"))
eq(fn("b/c.txt", "http://cdn.esm.sh/a"), new URL("http://cdn.esm.sh/b/c.txt"))
eq(fn("./b/c.txt", "http://cdn.esm.sh/a/"), new URL("http://cdn.esm.sh/a/b/c.txt"))
eq(fn("./b/c.txt", "http://cdn.esm.sh/a"), new URL("http://cdn.esm.sh/b/c.txt"))
eq(fn("../b/c.txt", "https://cdn.esm.sh/a/"), new URL("https://cdn.esm.sh/b/c.txt"))
eq(fn("../c/d.txt", "https://cdn.esm.sh/a/b"), new URL("https://cdn.esm.sh/c/d.txt"))

eq(fn("npm:react/file.txt"), new URL("npm:/react/file.txt"))
eq(fn("npm:@facebook/react"), new URL("npm:/@facebook/react/"))
eq(fn("./to/file.txt", "npm:react"), new URL("npm:/react/to/file.txt"))
eq(fn("./to/file.txt", "npm:react/"), new URL("npm:/react/to/file.txt"))

eq(fn("jsr:@scope/my-lib/b.txt"), new URL("jsr:/@scope/my-lib/b.txt"))
eq(fn("./a/b.txt", "jsr:///@scope/my-lib"), new URL("jsr:/@scope/my-lib/a/b.txt"))
eq(fn("./a/b.txt", "jsr:///@scope/my-lib/c"), new URL("jsr:/@scope/my-lib/a/b.txt"))
eq(fn("./a/b.txt", "jsr:///@scope/my-lib//c"), new URL("jsr:/@scope/my-lib/a/b.txt"))
eq(fn("../a/b.txt", "jsr:/@scope/my-lib///c/"), new URL("jsr:/@scope/my-lib/a/b.txt"))
eq(fn("./a/b.txt", "jsr:///@scope/my-lib/c/"), new URL("jsr:/@scope/my-lib/c/a/b.txt"))

err(() => fn("./a/b.txt", "data:text/plain;charset=utf-8;base64,aGVsbG8="))
err(() => fn("./a/b.txt", "blob:https://example.com/4800d2d8-a78c-4895-b68b-3690b69a0d6a"))
err(() => fn("./a/b.txt", "./path/")) // a base path must not be relative
err(() => fn("./a/b.txt")) // a relative path cannot be resolved on its own without a base path