diff --git a/registry.ts b/registry.ts index 05c66ec..f2fd36b 100644 --- a/registry.ts +++ b/registry.ts @@ -154,6 +154,66 @@ async function unpkgVersions(name: string): Promise { return m.map((x) => x[1]); } +interface PackageInfo { + parts: string[]; + scope: string; + packageName: string; + version: string; +} +function defaultInfo(that: RegistryUrl): PackageInfo { + const parts = that.url.split("/"); + const [packageName, version] = parts[4].split("@"); + if (parts[3] === undefined) { + throw new Error(`Package scope not found in ${that.url}`); + } + if (packageName === undefined) { + throw new Error(`Package name not found in ${that.url}`); + } + if (version === undefined) { + throw new Error(`Unable to find version in ${that.url}`); + } + return { + scope: parts[3], + packageName, + version, + parts, + }; +} + +function defaultScopeAt(that: RegistryUrl, version: string): string { + const { parts, packageName } = defaultInfo(that); + parts[4] = `${packageName}@${version}`; + return parts.join("/"); +} + +export class UnpkgScope implements RegistryUrl { + url: string; + + parts(): PackageInfo { + return defaultInfo(this); + } + + constructor(url: string) { + this.url = url; + } + + async all(): Promise { + const { scope, packageName } = this.parts(); + return await unpkgVersions(`${scope}/${packageName}`); + } + + at(version: string): RegistryUrl { + const url = defaultScopeAt(this, version); + return new UnpkgScope(url); + } + + version(): string { + return this.parts().version; + } + + regexp = /https?:\/\/unpkg\.com\/@[^\/\"\']*?\/[^\/\"\']*?\@[^\'\"]*/; +} + export class Unpkg implements RegistryUrl { url: string; @@ -239,6 +299,35 @@ export class Denopkg implements RegistryUrl { regexp = /https?:\/\/denopkg.com\/[^\/\"\']*?\/[^\/\"\']*?\@[^\'\"]*/; } +export class PikaScope implements RegistryUrl { + url: string; + + parts(): PackageInfo { + return defaultInfo(this); + } + + constructor(url: string) { + this.url = url; + } + + async all(): Promise { + const { scope, packageName } = this.parts(); + return await unpkgVersions(`${scope}/${packageName}`); + } + + at(version: string): RegistryUrl { + const url = defaultScopeAt(this, version); + return new PikaScope(url); + } + + version(): string { + return this.parts().version; + } + + regexp = + /https?:\/\/cdn\.pika\.dev(\/\_)?\/@[^\/\"\']*?\/[^\/\"\']*?\@[^\'\"]*/; +} + export class Pika implements RegistryUrl { url: string; @@ -266,6 +355,35 @@ export class Pika implements RegistryUrl { regexp = /https?:\/\/cdn.pika.dev(\/\_)?\/[^\/\"\']*?\@[^\'\"]*/; } +export class SkypackScope implements RegistryUrl { + url: string; + + parts(): PackageInfo { + return defaultInfo(this); + } + + constructor(url: string) { + this.url = url; + } + + async all(): Promise { + const { scope, packageName } = this.parts(); + return await unpkgVersions(`${scope}/${packageName}`); + } + + at(version: string): RegistryUrl { + const url = defaultScopeAt(this, version); + return new SkypackScope(url); + } + + version(): string { + return this.parts().version; + } + + regexp = + /https?:\/\/cdn\.skypack\.dev(\/\_)?\/@[^\/\"\']*?\/[^\/\"\']*?\@[^\'\"]*/; +} + export class Skypack implements RegistryUrl { url: string; @@ -293,6 +411,34 @@ export class Skypack implements RegistryUrl { regexp = /https?:\/\/cdn.skypack.dev(\/\_)?\/[^\/\"\']*?\@[^\'\"]*/; } +export class EsmShScope implements RegistryUrl { + url: string; + + parts(): PackageInfo { + return defaultInfo(this); + } + + constructor(url: string) { + this.url = url; + } + + async all(): Promise { + const { scope, packageName } = this.parts(); + return await unpkgVersions(`${scope}/${packageName}`); + } + + at(version: string): RegistryUrl { + const url = defaultScopeAt(this, version); + return new EsmShScope(url); + } + + version(): string { + return this.parts().version; + } + + regexp = /https?:\/\/esm\.sh\/@[^\/\"\']*?\/[^\/\"\']*?\@[^\'\"]*/; +} + export class EsmSh implements RegistryUrl { url: string; @@ -518,11 +664,15 @@ export class NestLand implements RegistryUrl { export const REGISTRIES = [ DenoLand, + UnpkgScope, Unpkg, Denopkg, Jspm, + PikaScope, Pika, + SkypackScope, Skypack, + EsmShScope, EsmSh, GithubRaw, GitlabRaw, diff --git a/registry_test.ts b/registry_test.ts index 09cd869..efd95f7 100644 --- a/registry_test.ts +++ b/registry_test.ts @@ -33,6 +33,15 @@ Deno.test("registryDenolandX", () => { assertEquals(vAt.url, "https://deno.land/x/foo@0.2.0/foo.ts"); }); +Deno.test("registryUnpkgScope", () => { + const url = "https://unpkg.com/@bar/foo@0.1.0/foo.ts"; + const v = lookup(url, REGISTRIES); + assert(v !== undefined); + + const vAt = v.at("0.2.0"); + assertEquals(vAt.url, "https://unpkg.com/@bar/foo@0.2.0/foo.ts"); +}); + Deno.test("registryUnpkg", () => { const url = "https://unpkg.com/foo@0.1.0/foo.ts"; const v = lookup(url, REGISTRIES); @@ -60,6 +69,15 @@ Deno.test("registryJspm", () => { assertEquals(vAt.url, "https://dev.jspm.io/npm:foo@0.2.0/"); }); +Deno.test("registryPikaScope", () => { + const url = "https://cdn.pika.dev/@bar/foo@0.1.0/"; + const v = lookup(url, REGISTRIES); + assert(v !== undefined); + + const vAt = v.at("0.2.0"); + assertEquals(vAt.url, "https://cdn.pika.dev/@bar/foo@0.2.0/"); +}); + Deno.test("registryPika", () => { const url = "https://cdn.pika.dev/foo@0.1.0/"; const v = lookup(url, REGISTRIES); @@ -69,6 +87,15 @@ Deno.test("registryPika", () => { assertEquals(vAt.url, "https://cdn.pika.dev/foo@0.2.0/"); }); +Deno.test("registrySkypackScope", () => { + const url = "https://cdn.skypack.dev/@bar/foo@0.1.0/"; + const v = lookup(url, REGISTRIES); + assert(v !== undefined); + + const vAt = v.at("0.2.0"); + assertEquals(vAt.url, "https://cdn.skypack.dev/@bar/foo@0.2.0/"); +}); + Deno.test("registrySkypack", () => { const url = "https://cdn.skypack.dev/foo@0.1.0/"; const v = lookup(url, REGISTRIES); @@ -78,6 +105,15 @@ Deno.test("registrySkypack", () => { assertEquals(vAt.url, "https://cdn.skypack.dev/foo@0.2.0/"); }); +Deno.test("registryEsmShScope", () => { + const url = "https://esm.sh/@bar/foo@0.1.0/"; + const v = lookup(url, REGISTRIES); + assert(v !== undefined); + + const vAt = v.at("0.2.0"); + assertEquals(vAt.url, "https://esm.sh/@bar/foo@0.2.0/"); +}); + Deno.test("registryEsmSh", () => { const url = "https://esm.sh/foo@0.1.0/"; const v = lookup(url, REGISTRIES);