UNPKG

@dbs-portal/core-module-registry

Version:

Core module registry system for automatic module discovery and registration

213 lines 7.3 kB
/** * Browser-compatible glob utilities * * Provides glob pattern matching that works in browser environments * while maintaining compatibility with the glob library API. */ class BrowserGlob { fileCache = new Map(); directoryCache = new Map(); /** * Main glob function - browser compatible */ async glob(pattern, options = {}) { const patterns = Array.isArray(pattern) ? pattern : [pattern]; const results = []; const cwd = options.cwd || '/'; for (const pat of patterns) { const matches = await this.matchPattern(pat, cwd, options); results.push(...matches); } // Remove duplicates and apply filters const uniqueResults = [...new Set(results)]; return this.applyFilters(uniqueResults, options); } /** * Synchronous glob (limited functionality in browser) */ globSync(pattern, options = {}) { // In browser, we can only work with cached data const patterns = Array.isArray(pattern) ? pattern : [pattern]; const results = []; const cwd = options.cwd || '/'; for (const pat of patterns) { const matches = this.matchPatternSync(pat, cwd, options); results.push(...matches); } const uniqueResults = [...new Set(results)]; return this.applyFilters(uniqueResults, options); } /** * Match a single pattern */ async matchPattern(pattern, cwd, options) { // For browser environment, we work with pre-loaded file lists const allFiles = this.getAllCachedFiles(cwd); return this.filterByPattern(allFiles, pattern, options); } /** * Match a single pattern synchronously */ matchPatternSync(pattern, cwd, options) { const allFiles = this.getAllCachedFiles(cwd); return this.filterByPattern(allFiles, pattern, options); } /** * Filter files by glob pattern */ filterByPattern(files, pattern, options) { const regex = this.globToRegex(pattern); const matches = []; for (const file of files) { if (regex.test(file)) { // Apply additional filters if (options.onlyDirectories && !this.isDirectory(file)) continue; if (options.onlyFiles && this.isDirectory(file)) continue; if (!options.dot && this.isDotFile(file)) continue; if (options.ignore && this.matchesIgnorePattern(file, options.ignore)) continue; matches.push(options.absolute ? file : this.makeRelative(file, options.cwd || '/')); } } return matches; } /** * Convert glob pattern to regex */ globToRegex(pattern) { let regexPattern = pattern .replace(/\./g, '\\.') .replace(/\*\*/g, '___DOUBLESTAR___') .replace(/\*/g, '[^/]*') .replace(/___DOUBLESTAR___/g, '.*') .replace(/\?/g, '[^/]'); // Handle character classes [abc] regexPattern = regexPattern.replace(/\[([^\]]+)\]/g, '[$1]'); // Handle negation [!abc] -> [^abc] regexPattern = regexPattern.replace(/\[!([^\]]+)\]/g, '[^$1]'); // Handle braces {a,b,c} -> (a|b|c) regexPattern = regexPattern.replace(/\{([^}]+)\}/g, (_match, content) => { const alternatives = content.split(',').map((alt) => alt.trim()); return `(${alternatives.join('|')})`; }); return new RegExp(`^${regexPattern}$`); } /** * Get all cached files for a directory */ getAllCachedFiles(cwd) { const files = []; // Get files from file cache for (const [path, _content] of this.fileCache) { if (path.startsWith(cwd)) { files.push(path); } } // Get directories from directory cache for (const [path, dirFiles] of this.directoryCache) { if (path.startsWith(cwd)) { files.push(path); files.push(...dirFiles.map(f => `${path}/${f}`)); } } return files; } /** * Apply additional filters */ applyFilters(files, options) { return files.filter(file => { if (options.onlyDirectories && !this.isDirectory(file)) return false; if (options.onlyFiles && this.isDirectory(file)) return false; if (!options.dot && this.isDotFile(file)) return false; if (options.ignore && this.matchesIgnorePattern(file, options.ignore)) return false; return true; }); } /** * Check if path is a directory */ isDirectory(path) { return this.directoryCache.has(path) || path.endsWith('/'); } /** * Check if file is a dot file */ isDotFile(path) { const basename = path.split('/').pop() || ''; return basename.startsWith('.') && basename !== '.' && basename !== '..'; } /** * Check if file matches ignore patterns */ matchesIgnorePattern(file, ignorePatterns) { return ignorePatterns.some(pattern => { const regex = this.globToRegex(pattern); return regex.test(file); }); } /** * Make path relative to cwd */ makeRelative(path, cwd) { if (path.startsWith(cwd)) { const relative = path.slice(cwd.length); return relative.startsWith('/') ? relative.slice(1) : relative; } return path; } /** * Pre-load file list for a directory (for browser usage) */ preloadDirectory(path, files) { this.directoryCache.set(path, files); } /** * Pre-load file content (for browser usage) */ preloadFile(path) { this.fileCache.set(path, []); } /** * Set mock directory structure (for testing) */ setMockStructure(structure) { this.directoryCache.clear(); this.fileCache.clear(); for (const [dir, files] of Object.entries(structure)) { this.directoryCache.set(dir, files); files.forEach(file => { this.fileCache.set(`${dir}/${file}`, []); }); } } /** * Clear all cached data */ clearCache() { this.fileCache.clear(); this.directoryCache.clear(); } } // Create browser glob instance const browserGlob = new BrowserGlob(); // Export main glob function for compatibility export const glob = browserGlob.glob.bind(browserGlob); export const globSync = browserGlob.globSync.bind(browserGlob); // Export utility functions export const preloadDirectory = browserGlob.preloadDirectory.bind(browserGlob); export const preloadFile = browserGlob.preloadFile.bind(browserGlob); export const setMockStructure = browserGlob.setMockStructure.bind(browserGlob); export const clearCache = browserGlob.clearCache.bind(browserGlob); // Export default object for compatibility export default browserGlob; // Export the class for advanced usage export { BrowserGlob }; //# sourceMappingURL=browser-glob.js.map