diff --git a/command/deno.json b/command/deno.json index c7d08be8..c910c52c 100644 --- a/command/deno.json +++ b/command/deno.json @@ -12,7 +12,8 @@ "./upgrade/provider/deno-land": "./upgrade/provider/deno_land.ts", "./upgrade/provider/github": "./upgrade/provider/github.ts", "./upgrade/provider/jsr": "./upgrade/provider/jsr.ts", - "./upgrade/provider/nest-land": "./upgrade/provider/nest_land.ts" + "./upgrade/provider/nest-land": "./upgrade/provider/nest_land.ts", + "./upgrade/provider/npm": "./upgrade/provider/npm.ts" }, "lock": false } diff --git a/command/upgrade/provider.ts b/command/upgrade/provider.ts index 0f882399..a27e8ad2 100644 --- a/command/upgrade/provider.ts +++ b/command/upgrade/provider.ts @@ -85,9 +85,10 @@ export abstract class Provider { } const registryUrl = this.getRegistryUrl(name, to); - const registry: string = registryUrl.startsWith("jsr:") - ? registryUrl - : new URL(main || `${name}.ts`, registryUrl).href; + const registry: string = + registryUrl.startsWith("jsr:") || registryUrl.startsWith("npm:") + ? registryUrl + : new URL(main || `${name}.ts`, registryUrl).href; const cmdArgs = ["install"]; diff --git a/command/upgrade/provider/npm.ts b/command/upgrade/provider/npm.ts new file mode 100644 index 00000000..60757471 --- /dev/null +++ b/command/upgrade/provider/npm.ts @@ -0,0 +1,66 @@ +import { Provider, type Versions } from "../provider.ts"; + +export type NpmProviderOptions = { + package: string; +} | { + scope: string; + name?: string; +}; + +export class NpmProvider extends Provider { + name = "npm"; + private readonly repositoryUrl = "https://registry.npmjs.org/"; + private readonly packageName?: string; + private readonly packageScope: string; + + constructor(options: NpmProviderOptions) { + super(); + this.packageScope = "package" in options + ? options.package.split("/")[0].slice(1) + : options.scope; + this.packageName = "package" in options + ? options.package.split("/")[1] + : options.name; + } + + async getVersions( + name: string, + ): Promise { + const response = await fetch( + `${this.repositoryUrl}/@${this.packageScope}/${this.packageName ?? name}`, + ); + if (!response.ok) { + throw new Error( + "couldn't fetch the latest version - try again after sometime", + ); + } + + const { "dist-tags": { latest }, versions } = await response + .json() as NpmApiPackageMetadata; + + return { + latest, + versions: Object.keys(versions).reverse(), + }; + } + + getRepositoryUrl(name: string): string { + return new URL( + `@${this.packageScope}/${this.packageName ?? name}`, + this.repositoryUrl, + ).href; + } + + getRegistryUrl(name: string, version: string): string { + return `npm:@${this.packageScope}/${this.packageName ?? name}@${version}`; + } +} + +type NpmApiPackageMetadata = { + "dist-tags": { + latest: string; + }; + versions: { + [version: string]: unknown; + }; +};