Skip to main content
Glama
version.ts6.27 kB
/** * @fileoverview Central version management module for DeepSource MCP Server * * This module provides a single source of truth for version information, * reading from package.json at build time with fallback support for runtime. */ import { readFileSync } from 'fs'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; /** * Interface representing parsed version information */ export interface VersionInfo { /** Full version string (e.g., "1.5.0") */ version: string; /** Major version number */ major: number; /** Minor version number */ minor: number; /** Patch version number */ patch: number; /** Pre-release version (e.g., "beta.1") */ prerelease?: string; /** Build metadata (e.g., "20240101") */ build?: string; } /** * Get the directory name for the current module * Works with ES modules */ function getCurrentDir(): string { try { const __filename = fileURLToPath(import.meta.url); return dirname(__filename); } catch { // Fallback for environments where import.meta.url is not available return process.cwd(); } } /** * Read version from package.json * @returns The version string from package.json or null if unable to read */ function readVersionFromPackageJson(): string | null { try { const currentDir = getCurrentDir(); // Try multiple paths to find package.json const possiblePaths = [ join(currentDir, '../../package.json'), // From src/version.ts join(currentDir, '../package.json'), // From dist/version.js join(process.cwd(), 'package.json'), // From current working directory ]; for (const packagePath of possiblePaths) { try { const packageContent = readFileSync(packagePath, 'utf-8'); const packageJson = JSON.parse(packageContent) as { version?: string }; if (packageJson.version) { return packageJson.version; } } catch { // Try next path continue; } } return null; } catch { return null; } } /** * Parse a semver version string into components * @param versionString - The version string to parse * @returns Parsed version information or null if invalid */ export function parseVersion(versionString: string): VersionInfo | null { // Regex for semantic versioning // Matches: major.minor.patch[-prerelease][+build] const semverRegex = /^(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9.-]+))?(?:\+([a-zA-Z0-9.-]+))?$/; const match = versionString.match(semverRegex); if (!match) { return null; } const [, majorStr, minorStr, patchStr, prerelease, build] = match; // These are guaranteed to be strings when the regex matches // The regex requires \d+ for major, minor, and patch if (!majorStr || !minorStr || !patchStr) { // This should never happen due to regex, but satisfies TypeScript return null; } return { version: versionString, major: parseInt(majorStr, 10), minor: parseInt(minorStr, 10), patch: parseInt(patchStr, 10), ...(prerelease && { prerelease }), ...(build && { build }), }; } /** * Validate if a string is a valid semver version * @param versionString - The version string to validate * @returns True if valid semver format */ export function validateVersion(versionString: string): boolean { return parseVersion(versionString) !== null; } /** * Compare two semver versions * @param v1 - First version * @param v2 - Second version * @returns -1 if v1 < v2, 0 if v1 === v2, 1 if v1 > v2 */ export function compareVersions(v1: string, v2: string): number { const version1 = parseVersion(v1); const version2 = parseVersion(v2); if (!version1 || !version2) { throw new Error('Invalid version format'); } // Compare major if (version1.major !== version2.major) { return version1.major < version2.major ? -1 : 1; } // Compare minor if (version1.minor !== version2.minor) { return version1.minor < version2.minor ? -1 : 1; } // Compare patch if (version1.patch !== version2.patch) { return version1.patch < version2.patch ? -1 : 1; } // Compare prerelease (absence means higher version) if (version1.prerelease && !version2.prerelease) { return -1; } if (!version1.prerelease && version2.prerelease) { return 1; } if (version1.prerelease && version2.prerelease) { return version1.prerelease.localeCompare(version2.prerelease); } return 0; } // Initialize version - try to read from package.json, fallback to build-time constant function determineVersion(): string { const packageVersion = readVersionFromPackageJson(); if (packageVersion && validateVersion(packageVersion)) { return packageVersion; } // This will be replaced during build process const buildVersion = '__BUILD_VERSION__'; // If still the placeholder, use a fallback version if (buildVersion === '__BUILD_VERSION__' || !validateVersion(buildVersion)) { return '0.0.0-dev'; } return buildVersion; } const VERSION = determineVersion(); /** * The current version of the DeepSource MCP Server * @constant */ export { VERSION }; /** * Get the current version of the DeepSource MCP Server * @returns The current version string */ export function getVersion(): string { return VERSION; } /** * Get detailed version information * @returns Parsed version information */ export function getVersionInfo(): VersionInfo { const info = parseVersion(VERSION); if (!info) { // Should never happen due to validation above, but TypeScript needs this return { version: VERSION, major: 0, minor: 0, patch: 0, }; } return info; } /** * Get a formatted version string for display * @param includePrerelease - Whether to include prerelease info * @param includeBuild - Whether to include build metadata * @returns Formatted version string */ export function getFormattedVersion(includePrerelease = true, includeBuild = false): string { const info = getVersionInfo(); let formatted = `${info.major}.${info.minor}.${info.patch}`; if (includePrerelease && info.prerelease) { formatted += `-${info.prerelease}`; } if (includeBuild && info.build) { formatted += `+${info.build}`; } return formatted; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sapientpants/deepsource-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server