Skip to main content
Glama
swift_evolution.py9.63 kB
""" Swift Evolution Module ====================== Provides access to Swift Evolution proposals through swift.org's official JSON feed. This module enables searching and retrieving information about Swift language evolution proposals, including their status, implementation versions, and rationale. Key Features: - Live data from swift.org (no authentication required) - Intelligent caching to minimize network requests - Relevance-based search scoring - Version-specific proposal filtering Data Source: https://download.swift.org/swift-evolution/v1/evolution.json """ import re import urllib.request import urllib.parse import json import time from typing import Dict, Optional, List class SwiftEvolution: """ Search and analyze Swift Evolution proposals using swift.org data feed. This class provides methods to search proposals by feature name or Swift version, and retrieve detailed information about specific proposals. It implements a simple caching mechanism to reduce API calls and improve response times. Attributes: EVOLUTION_JSON_URL: Official swift.org JSON feed endpoint GITHUB_WEB_BASE: Base URL for viewing proposals on GitHub GITHUB_RAW_BASE: Base URL for raw proposal markdown content """ EVOLUTION_JSON_URL = "https://download.swift.org/swift-evolution/v1/evolution.json" GITHUB_WEB_BASE = "https://github.com/swiftlang/swift-evolution" GITHUB_RAW_BASE = "https://raw.githubusercontent.com/swiftlang/swift-evolution/main/proposals" def __init__(self): """Initialize with empty cache and TTL settings.""" self.cache = None # Cached JSON data from swift.org self.cache_time = 0 # Timestamp of last cache update self.cache_ttl = 3600 # Cache Time-To-Live: 1 hour def _fetch_evolution_data(self) -> Optional[Dict]: """ Fetch and cache the evolution.json data from swift.org. This method implements a simple TTL-based caching mechanism to avoid excessive network requests. The cache expires after 1 hour. Returns: Dict containing proposal data from swift.org, or None if fetch fails. """ # Return cached data if still valid (within TTL window) if self.cache and (time.time() - self.cache_time) < self.cache_ttl: return self.cache try: # Create request with User-Agent header (required by some servers) req = urllib.request.Request( self.EVOLUTION_JSON_URL, headers={'User-Agent': 'AppleDeepDocs-MCP'} ) # Fetch fresh data from swift.org with urllib.request.urlopen(req, timeout=15) as response: data = json.loads(response.read().decode('utf-8')) # Update cache with fresh data self.cache = data self.cache_time = time.time() return data except Exception as e: # Return None to indicate fetch failure # Caller should handle this gracefully return None def search_proposals(self, feature: str) -> Dict: """ Search Swift Evolution proposals by feature name, version, or status. This method implements a relevance-based scoring system: - Exact version match: +100 points - Partial version match: +50 points - Status match: +15 points (e.g., 'rejected', 'withdrawn', 'returnedForRevision') - Feature in title: +10 points - Feature in summary: +5 points Args: feature: Feature name, Swift version, or proposal status to search for Examples: 'async', 'Swift 6', 'actors', 'property wrapper', 'rejected', 'withdrawn', 'returnedForRevision' Returns: Dictionary containing: - feature: The search term used - total_found: Number of matching proposals - proposals: List of matching proposals sorted by relevance - available_versions: List of Swift versions with implemented proposals """ data = self._fetch_evolution_data() if not data: return { 'error': 'Failed to fetch Swift Evolution data', 'feature': feature, 'suggestion': 'Check your internet connection' } proposals = data.get('proposals', []) feature_lower = feature.lower() results = [] # Extract version number if user is searching for a Swift version # Pattern matches: "swift 6", "Swift 6.0", "swift6.1", etc. version_match = re.search(r'swift\s*(\d+\.?\d*)', feature_lower) search_version = version_match.group(1) if version_match else None for proposal in proposals: score = 0 status = proposal.get('status', {}) impl_version = status.get('version', '') # Version-specific scoring if search_version: if impl_version == search_version: score += 100 # Exact version match (e.g., "6.0" == "6.0") elif impl_version and impl_version.startswith(search_version): score += 50 # Partial match (e.g., "6.0" matches "6") # Text-based scoring title = proposal.get('title', '').lower() summary = proposal.get('summary', '').lower() status_state = status.get('state', '').lower() if feature_lower in title: score += 10 # Title matches are more relevant if feature_lower in summary: score += 5 # Summary matches are less relevant if feature_lower in status_state: score += 15 # Status matches are highly relevant for finding proposals by state # Only include proposals with positive scores if score > 0: results.append({ 'se_number': proposal.get('id', ''), 'title': proposal.get('title', ''), 'status': status.get('state', 'unknown'), 'version': impl_version or 'N/A', # Truncate long summaries for readability 'summary': proposal.get('summary', '')[:200] + '...' if len(proposal.get('summary', '')) > 200 else proposal.get('summary', ''), 'github_url': f"{self.GITHUB_WEB_BASE}/blob/main/proposals/{proposal.get('link', '')}", 'relevance_score': score }) # Sort by relevance score (highest first) results.sort(key=lambda x: x['relevance_score'], reverse=True) return { 'feature': feature, 'total_found': len(results), 'proposals': results[:20], # Top 20 results 'available_versions': data.get('implementationVersions', []) } def get_proposal(self, se_number: str) -> Dict: """ Get detailed information about a specific Swift Evolution proposal. This method handles various input formats for SE numbers: - Full format: 'SE-0413' - Short format: '0413' or '413' - Case insensitive: 'se-0413' Args: se_number: The Swift Evolution proposal number Returns: Dictionary containing: - se_number: Normalized proposal ID - title: Proposal title - status: Current state (e.g., 'implemented', 'accepted') - version: Swift version where implemented - summary: Full proposal summary - authors: List of proposal authors - github_url: Link to view on GitHub - raw_url: Direct link to markdown content - swift_org_url: Official swift.org link """ data = self._fetch_evolution_data() if not data: return { 'error': 'Failed to fetch Swift Evolution data', 'se_number': se_number, 'suggestion': 'Check your internet connection' } # Normalize SE number to standard format (SE-XXXX) se_num = se_number.upper() if not se_num.startswith('SE-'): # Pad with zeros to make 4 digits (e.g., '413' -> 'SE-0413') se_num = f'SE-{se_num.zfill(4)}' # Search for the proposal in the data proposals = data.get('proposals', []) proposal = next((p for p in proposals if p.get('id', '').upper() == se_num), None) if not proposal: return { 'error': f'Proposal {se_num} not found', 'se_number': se_num, 'suggestion': f'Visit https://www.swift.org/swift-evolution/ to browse proposals' } status = proposal.get('status', {}) authors = proposal.get('authors', []) return { 'se_number': proposal.get('id', ''), 'title': proposal.get('title', ''), 'status': status.get('state', 'unknown'), 'version': status.get('version', 'N/A'), 'summary': proposal.get('summary', ''), 'authors': [a.get('name', 'Unknown') for a in authors], 'github_url': f"{self.GITHUB_WEB_BASE}/blob/main/proposals/{proposal.get('link', '')}", 'raw_url': f"{self.GITHUB_RAW_BASE}/{proposal.get('link', '')}", 'swift_org_url': f'https://www.swift.org/swift-evolution/#?id={proposal.get("id", "")}' } # Module-level instance evolution = SwiftEvolution()

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/Ahrentlov/appledeepdoc-mcp'

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