UNPKG

mcp-adr-analysis-server

Version:

MCP server for analyzing Architectural Decision Records and project architecture

272 lines 9.16 kB
/** * Resource Versioning and Metadata Tracking * * Provides version control for MCP resources, enabling: * - Semantic versioning (MAJOR.MINOR.PATCH) * - Backward compatibility checking * - Version migration support * - Metadata tracking (creation, updates, changelog) */ /** * Version comparison result */ export var VersionComparisonResult; (function (VersionComparisonResult) { VersionComparisonResult["MAJOR_BREAKING"] = "major_breaking"; VersionComparisonResult["MINOR_COMPATIBLE"] = "minor_compatible"; VersionComparisonResult["PATCH_COMPATIBLE"] = "patch_compatible"; VersionComparisonResult["EQUAL"] = "equal"; VersionComparisonResult["OLDER"] = "older"; })(VersionComparisonResult || (VersionComparisonResult = {})); /** * Parse semantic version string to object */ export function parseVersion(versionString) { const match = versionString.match(/^(\d+)\.(\d+)\.(\d+)$/); if (!match) { throw new Error(`Invalid semantic version: ${versionString}`); } return { major: parseInt(match[1], 10), minor: parseInt(match[2], 10), patch: parseInt(match[3], 10), }; } /** * Convert semantic version object to string */ export function versionToString(version) { return `${version.major}.${version.minor}.${version.patch}`; } /** * Compare two semantic versions * @returns VersionComparisonResult indicating relationship */ export function compareVersions(current, requested) { const currentV = parseVersion(current); const requestedV = parseVersion(requested); // Equal versions if (currentV.major === requestedV.major && currentV.minor === requestedV.minor && currentV.patch === requestedV.patch) { return VersionComparisonResult.EQUAL; } // Current is older than requested if (currentV.major < requestedV.major || (currentV.major === requestedV.major && currentV.minor < requestedV.minor) || (currentV.major === requestedV.major && currentV.minor === requestedV.minor && currentV.patch < requestedV.patch)) { return VersionComparisonResult.OLDER; } // Current is newer - check compatibility if (currentV.major > requestedV.major) { return VersionComparisonResult.MAJOR_BREAKING; } if (currentV.minor > requestedV.minor) { return VersionComparisonResult.MINOR_COMPATIBLE; } return VersionComparisonResult.PATCH_COMPATIBLE; } /** * Check if two versions are compatible (same major version) */ export function isCompatible(version1, version2) { const v1 = parseVersion(version1); const v2 = parseVersion(version2); return v1.major === v2.major; } /** * Increment version based on change type */ export function incrementVersion(current, changeType) { const version = parseVersion(current); switch (changeType) { case 'major': return versionToString({ major: version.major + 1, minor: 0, patch: 0 }); case 'minor': return versionToString({ major: version.major, minor: version.minor + 1, patch: 0 }); case 'patch': return versionToString({ major: version.major, minor: version.minor, patch: version.patch + 1 }); default: throw new Error(`Invalid change type: ${changeType}`); } } /** * Create initial resource metadata */ export function createResourceMetadata(version = '1.0.0') { const now = new Date().toISOString(); return { version, createdAt: now, updatedAt: now, schemaVersion: version, }; } /** * Update resource metadata with new version */ export function updateResourceMetadata(current, newVersion, changes, breakingChanges) { const now = new Date().toISOString(); const changelogEntry = { version: newVersion, date: now, changes, }; // Only add breakingChanges if provided if (breakingChanges) { changelogEntry.breakingChanges = breakingChanges; } return { ...current, version: newVersion, updatedAt: now, changelog: [...(current.changelog || []), changelogEntry], }; } /** * Mark resource as deprecated */ export function deprecateResource(metadata, reason, migration, removedIn) { const deprecationNotice = { deprecatedIn: metadata.version, reason, migration, }; // Only add removedIn if provided if (removedIn) { deprecationNotice.removedIn = removedIn; } return { ...metadata, deprecationNotice, }; } /** * Check if resource is deprecated */ export function isDeprecated(metadata) { return metadata.deprecationNotice !== undefined; } /** * Extract version from URI search parameters */ export function extractVersionFromParams(searchParams) { if (!searchParams) { return null; } return searchParams.get('version'); } /** * Validate requested version against available versions */ export function validateVersionRequest(requested, current, supportedVersions) { // No version requested - use current if (!requested) { return { valid: true, version: current }; } // Check if requested version is supported if (!supportedVersions.includes(requested)) { return { valid: false, version: current, warning: `Version ${requested} not supported. Using current version ${current}. Supported: ${supportedVersions.join(', ')}`, }; } // Check compatibility const comparison = compareVersions(current, requested); if (comparison === VersionComparisonResult.MAJOR_BREAKING) { return { valid: true, version: requested, warning: `Warning: Version ${requested} has breaking changes from current ${current}`, }; } return { valid: true, version: requested }; } /** * Generate version compatibility matrix */ export function generateCompatibilityMatrix(versions) { const matrix = new Map(); for (const version of versions) { const compatible = versions.filter((v) => isCompatible(version, v)); matrix.set(version, compatible); } return matrix; } /** * Get changelog for specific version range */ export function getChangelogForRange(metadata, fromVersion, toVersion) { if (!metadata.changelog) { return []; } const from = parseVersion(fromVersion); const to = parseVersion(toVersion); return metadata.changelog.filter((entry) => { const entryVersion = parseVersion(entry.version); // Version is within range (exclusive of fromVersion, inclusive of toVersion) const isAfterFrom = entryVersion.major > from.major || (entryVersion.major === from.major && entryVersion.minor > from.minor) || (entryVersion.major === from.major && entryVersion.minor === from.minor && entryVersion.patch > from.patch); const isBeforeOrEqualTo = entryVersion.major < to.major || (entryVersion.major === to.major && entryVersion.minor < to.minor) || (entryVersion.major === to.major && entryVersion.minor === to.minor && entryVersion.patch <= to.patch); return isAfterFrom && isBeforeOrEqualTo; }); } /** * Extract breaking changes from changelog */ export function getBreakingChanges(metadata) { if (!metadata.changelog) { return []; } return metadata.changelog.filter((entry) => entry.breakingChanges && entry.breakingChanges.length > 0); } /** * Format metadata for display */ export function formatMetadata(metadata) { const lines = [ `Version: ${metadata.version}`, `Schema: ${metadata.schemaVersion}`, `Created: ${metadata.createdAt}`, `Updated: ${metadata.updatedAt}`, ]; if (metadata.deprecationNotice) { lines.push(''); lines.push('⚠️ DEPRECATED'); lines.push(`Deprecated in: ${metadata.deprecationNotice.deprecatedIn}`); if (metadata.deprecationNotice.removedIn) { lines.push(`Will be removed in: ${metadata.deprecationNotice.removedIn}`); } lines.push(`Reason: ${metadata.deprecationNotice.reason}`); lines.push(`Migration: ${metadata.deprecationNotice.migration}`); } if (metadata.changelog && metadata.changelog.length > 0) { lines.push(''); lines.push('Recent Changes:'); const recentChanges = metadata.changelog.slice(-3).reverse(); for (const entry of recentChanges) { lines.push(` v${entry.version} (${entry.date})`); for (const change of entry.changes) { lines.push(` - ${change}`); } if (entry.breakingChanges && entry.breakingChanges.length > 0) { lines.push(' ⚠️ Breaking Changes:'); for (const breaking of entry.breakingChanges) { lines.push(` - ${breaking}`); } } } } return lines.join('\n'); } //# sourceMappingURL=resource-versioning.js.map