resolveSpecifier(input: string): ResolvedSpecifier
Resolves a user-typed package argument to a module specifier.
Version suffixes ride along unchanged, so wav@0.2.0 becomes
jsr:@binstruct/wav@0.2.0. Bare-name resolution is unconditional: there is
no registry lookup and no fallback to another scope, so xhb resolves to
jsr:@binstruct/xhb and fails at load time rather than finding
@hertzg/xhb.
A path is anchored to the working directory and returned as a file:// URL,
so that discovery and import() — which disagree about what a relative
specifier is relative to — resolve it to the same module. Reading
Deno.cwd() is the one thing this function needs from outside its argument,
and only for that form.
Whether the path names a file or a directory is left open. Both are the
"path" form, because a directory and the module inside it are
indistinguishable as strings and file:///abs/pkg is as much a directory as
./pkg is; the CLI settles the question by stat'ing the resolved target
(inspectLocalTarget in ./target.ts). pkg/, ./pkg and /abs/pkg
therefore anchor to one URL and reach one decision — resolve normalizes
the trailing slash away.
A bare name implies jsr: and the @binstruct scope
A bare name implies jsr: and the @binstruct scope
import { assertEquals } from "@std/assert"; import { resolveSpecifier } from "./specifier.ts"; const resolved = resolveSpecifier("png"); assertEquals(resolved.specifier, "jsr:@binstruct/png"); assertEquals(resolved.short, "png"); assertEquals(resolved.form, "bare"); assertEquals(resolved.shorthand, true);
A scope, a scheme and a path
A scope, a scheme and a path
import { assertEquals } from "@std/assert"; import { toFileUrl } from "@std/path"; import { resolveSpecifier } from "./specifier.ts"; assertEquals(resolveSpecifier("@hertzg/xhb").specifier, "jsr:@hertzg/xhb"); assertEquals(resolveSpecifier("npm:foo").specifier, "npm:foo"); const local = resolveSpecifier("./local/mod.ts"); assertEquals(local.specifier, toFileUrl(`${Deno.cwd()}/local/mod.ts`).href); assertEquals(local.short, "./local/mod.ts"); assertEquals(local.form, "path");
A directory and the module inside it are the same form
A directory and the module inside it are the same form
import { assertEquals } from "@std/assert"; import { resolveSpecifier } from "./specifier.ts"; assertEquals(resolveSpecifier("./local").form, "path"); assertEquals(resolveSpecifier("./local/mod.mts").form, "path"); assertEquals(resolveSpecifier("file:///abs/local").form, "scheme");
A slash outside a scope is a path, whatever it is spelled like
A slash outside a scope is a path, whatever it is spelled like
import { assertEquals } from "@std/assert"; import { resolveSpecifier } from "./specifier.ts"; assertEquals(resolveSpecifier("local/").form, "path"); assertEquals(resolveSpecifier("nested/inner").form, "path"); assertEquals( resolveSpecifier("local/").specifier, resolveSpecifier("./local").specifier, );
Only a package-hosting scheme is a scheme; any other colon is ordinary
Only a package-hosting scheme is a scheme; any other colon is ordinary
import { assertEquals } from "@std/assert"; import { resolveSpecifier } from "./specifier.ts"; assertEquals(resolveSpecifier("node:fs").form, "bare"); assertEquals(resolveSpecifier("node:evil.ts").form, "path"); assertEquals(resolveSpecifier("data:text/plain,x").form, "path"); assertEquals(resolveSpecifier("my:dir/mod.ts").form, "path"); assertEquals(resolveSpecifier("gopher:x").form, "bare");
The input, its resolved specifier, its short form and how it was classified.