Files
pnpm/env/plugin-commands-env/src/parseNodeSpecifier.ts
2025-03-02 13:17:09 +01:00

45 lines
1.7 KiB
TypeScript

import { PnpmError } from '@pnpm/error'
export interface NodeSpecifier {
releaseChannel: string
useNodeVersion: string
}
const isStableVersion = (version: string) => /^\d+\.\d+\.\d+$/.test(version)
const STABLE_RELEASE_ERROR_HINT = 'The correct syntax for stable release is strictly X.Y.Z or release/X.Y.Z'
export function parseNodeSpecifier (specifier: string): NodeSpecifier {
if (specifier.includes('/')) {
const [releaseChannel, useNodeVersion] = specifier.split('/')
if (releaseChannel === 'release') {
if (!isStableVersion(useNodeVersion)) {
throw new PnpmError('INVALID_NODE_VERSION', `"${specifier}" is not a valid Node.js version`, {
hint: STABLE_RELEASE_ERROR_HINT,
})
}
} else if (!useNodeVersion.includes(releaseChannel)) {
throw new PnpmError('MISMATCHED_RELEASE_CHANNEL', `Node.js version (${useNodeVersion}) must contain the release channel (${releaseChannel})`)
}
return { releaseChannel, useNodeVersion }
}
const prereleaseMatch = specifier.match(/^\d+\.\d+\.\d+-(nightly|rc|test|v8-canary)(\..+)$/)
if (prereleaseMatch != null) {
return { releaseChannel: prereleaseMatch[1], useNodeVersion: specifier }
}
if (isStableVersion(specifier)) {
return { releaseChannel: 'release', useNodeVersion: specifier }
}
let hint: string | undefined
if (['nightly', 'rc', 'test', 'v8-canary'].includes(specifier)) {
hint = `The correct syntax for ${specifier} release is strictly X.Y.Z-${specifier}.W`
} else if (/^\d+\.\d+$/.test(specifier) || /^\d+$/.test(specifier) || ['release', 'stable', 'latest'].includes(specifier)) {
hint = STABLE_RELEASE_ERROR_HINT
}
throw new PnpmError('INVALID_NODE_VERSION', `"${specifier}" is not a valid Node.js version`, { hint })
}