Skip to main content
Glama

CTX: Context as Code (CaC) tool

by context-hub
MIT License
235
  • Apple
  • Linux
SymfonyFinder.php5.98 kB
<?php declare(strict_types=1); namespace Butschster\ContextGenerator\Source\File; use Butschster\ContextGenerator\Config\Exclude\ExcludeRegistryInterface; use Butschster\ContextGenerator\Lib\Finder\FinderInterface; use Butschster\ContextGenerator\Lib\Finder\FinderResult; use Butschster\ContextGenerator\Lib\TreeBuilder\FileTreeBuilder; use Butschster\ContextGenerator\Source\Fetcher\FilterableSourceInterface; use Symfony\Component\Finder\Finder; use Symfony\Component\Finder\SplFileInfo; /** * Implementation of FinderInterface using Symfony's Finder component */ final readonly class SymfonyFinder implements FinderInterface { public function __construct( private ExcludeRegistryInterface $excludeRegistry, private FileTreeBuilder $fileTreeBuilder = new FileTreeBuilder(), ) {} /** * Find files based on the given source configuration * * @param FilterableSourceInterface $source Source configuration with filter criteria * @param string $basePath Optional base path to normalize file paths in the tree view * @param array $options Additional options for the finder * @return FinderResult The result containing found files and tree view */ public function find(FilterableSourceInterface $source, string $basePath = '', array $options = []): FinderResult { $finder = new Finder(); $finder->files(); // Configure in() with directories and files $directories = $source->in(); $files = $source->files(); if (!empty($directories)) { $finder->in($directories); } if (!empty($files)) { $finder->append($files); } // Configure name pattern for file matching $namePattern = $source->name(); if ($namePattern !== null) { $finder->name($namePattern); } // Configure path pattern $pathPattern = $source->path(); if ($pathPattern !== null) { $finder->path($pathPattern); } // Configure notPath pattern $notPathPattern = $source->notPath(); if ($notPathPattern !== null) { $finder->notPath($notPathPattern); } // Configure contains pattern $containsPattern = $source->contains(); if ($containsPattern !== null) { $finder->contains($containsPattern); } // Configure notContains pattern $notContainsPattern = $source->notContains(); if ($notContainsPattern !== null) { $finder->notContains($notContainsPattern); } // Configure size constraints $sizeConstraints = $source->size(); if ($sizeConstraints !== null) { $finder->size($sizeConstraints); } // Configure date constraints $dateConstraints = $source->date(); if ($dateConstraints !== null) { $finder->date($dateConstraints); } // Configure ignoreUnreadableDirs if ($source->ignoreUnreadableDirs()) { $finder->ignoreUnreadableDirs(); } // Apply depth constraint if maxDepth is set if (isset($options['maxDepth']) && $options['maxDepth'] > 0) { $finder->depth('<= ' . $options['maxDepth']); } $finder->sortByName(); // Check for maxFiles limit $maxFiles = $source->maxFiles(); $hasLimit = $maxFiles !== null && $maxFiles > 0; // Generate tree view (always on all files for consistency) $treeView = $this->generateTreeView($finder, $basePath, $options); // Get files with limit if needed if ($hasLimit) { $limitedFiles = []; $count = 0; foreach ($finder as $file) { $limitedFiles[] = $file; $count++; if ($count >= $maxFiles) { break; } } return new FinderResult( files: $limitedFiles, treeView: $treeView, ); } // No limit, filter out excluded files $files = []; foreach ($finder as $file) { // Skip files that would be excluded by path patterns if ($this->shouldExcludeFile($this->getPath($file, $basePath))) { continue; } $files[] = $file; } // Return filtered files return new FinderResult( files: $files, treeView: $treeView, ); } /** * Generate a tree view of the found files * * @param Finder $finder The Symfony Finder instance with results * @param string $basePath Optional base path to normalize file paths * @param array $options Additional options for tree view generation * @return string Text representation of the file tree */ private function generateTreeView(Finder $finder, string $basePath, array $options): string { $filePaths = []; foreach ($finder as $file) { // Skip excluded files in tree view if ($this->shouldExcludeFile($this->getPath($file, $basePath))) { continue; } $filePaths[] = $file->getRealPath(); } if (empty($filePaths)) { return "No files found.\n"; } return $this->fileTreeBuilder->buildTree($filePaths, $basePath, $options); } /** * Check if a file should be excluded based on global exclusion patterns */ private function shouldExcludeFile(string $filePath): bool { return $this->excludeRegistry->shouldExclude($filePath); } private function getPath(SplFileInfo|\SplFileInfo $file, string $basePath) { if ($file instanceof SplFileInfo) { return $file->getRelativePathname(); } return \ltrim(\str_replace($basePath, '', $file->getRealPath()), '/'); } }

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/context-hub/generator'

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