Files
pnpm/resolving/jsr-specifier-parser/src/index.ts

65 lines
2.0 KiB
TypeScript

import { PnpmError } from '@pnpm/error'
export interface JsrSpec {
jsrPkgName: string
npmPkgName: string
// A versionSelector may be a semver range (e.g. ^1.0.0), exact version (e.g. 2.3.4), or a dist-tag (e.g. "latest").
versionSelector?: string
}
export function parseJsrSpecifier (rawSpecifier: string, alias?: string): JsrSpec | null {
if (!rawSpecifier.startsWith('jsr:')) return null
rawSpecifier = rawSpecifier.substring('jsr:'.length)
// syntax: jsr:@<scope>/<name>[@<version_selector>]
if (rawSpecifier[0] === '@') {
const index = rawSpecifier.lastIndexOf('@')
// syntax: jsr:@<scope>/<name>
if (index === 0) {
return {
jsrPkgName: rawSpecifier,
npmPkgName: jsrToNpmPackageName(rawSpecifier),
}
}
// syntax: jsr:@<scope>/<name>@<version_selector>
const jsrPkgName = rawSpecifier.substring(0, index)
return {
jsrPkgName,
npmPkgName: jsrToNpmPackageName(jsrPkgName),
versionSelector: rawSpecifier.substring(index + '@'.length),
}
}
// syntax: jsr:<name>@<version_selector> (invalid)
if (rawSpecifier.includes('@')) {
throw new PnpmError('MISSING_JSR_PACKAGE_SCOPE', 'Package names from JSR must have a scope')
}
if (!alias) {
throw new PnpmError('INVALID_JSR_SPECIFIER', `JSR specifier '${rawSpecifier}' is missing a package name`)
}
// syntax: jsr:<spec>
return {
versionSelector: rawSpecifier,
jsrPkgName: alias,
npmPkgName: jsrToNpmPackageName(alias),
}
}
function jsrToNpmPackageName (jsrPkgName: string): string {
if (jsrPkgName[0] !== '@') {
throw new PnpmError('MISSING_JSR_PACKAGE_SCOPE', 'Package names from JSR must have a scope')
}
const sepIndex = jsrPkgName.indexOf('/')
if (sepIndex === -1) {
throw new PnpmError('INVALID_JSR_PACKAGE_NAME', `The package name '${jsrPkgName}' is invalid`)
}
const scope = jsrPkgName.substring(0, sepIndex)
const name = jsrPkgName.substring(sepIndex + '/'.length)
return `@jsr/${scope.substring(1)}__${name}`
}