import * as fs from 'fs'; import * as path from 'path'; import * as smartfsModule from '@push.rocks/smartfs'; // Create a smartfs instance with Node.js provider const smartfs = new smartfsModule.SmartFs(new smartfsModule.SmartFsProviderNode()); /** * FsHelpers provides filesystem utility methods for tsbuild. * All methods are static for convenience. */ export class FsHelpers { /** * The smartfs instance for filesystem operations */ public static readonly smartfs = smartfs; /** * List files matching a glob pattern like './ts/**\/*.ts' * Parses the pattern to extract base directory and filter pattern */ public static async listFilesWithGlob(basePath: string, globPattern: string): Promise { // Remove leading ./ if present const pattern = globPattern.replace(/^\.\//, ''); // Find the first directory part before any glob characters const globChars = ['*', '?', '{', '[']; let baseDir = basePath; // Find where the glob pattern starts const parts = pattern.split('/'); const staticParts: string[] = []; const filterParts: string[] = []; let foundGlob = false; for (const part of parts) { if (!foundGlob && !globChars.some(c => part.includes(c))) { staticParts.push(part); } else { foundGlob = true; filterParts.push(part); } } // Build the base directory if (staticParts.length > 0) { baseDir = path.join(basePath, ...staticParts); } // Build the filter pattern (just the filename part, ignoring ** for directories) // The recursive() handles the ** part const fileFilter = filterParts[filterParts.length - 1] || '*'; // Check if we need recursive search const needsRecursive = filterParts.some(p => p === '**' || p.includes('**')); let dirBuilder = smartfs.directory(baseDir); if (needsRecursive) { dirBuilder = dirBuilder.recursive(); } try { const entries = await dirBuilder.filter(fileFilter).list(); return entries.filter(e => e.isFile).map(e => e.path); } catch { // Directory doesn't exist or other error return []; } } /** * Extract source folder name from a glob pattern * './ts_core/**\/*.ts' → 'ts_core' * 'ts_foo/**\/*.ts' → 'ts_foo' */ public static extractSourceFolder(pattern: string): string | null { const match = pattern.match(/^\.?\/?([^\/\*]+)/); return match ? match[1] : null; } /** * Get the current working directory */ public static getCwd(): string { return process.cwd(); } /** * Get the package directory (where package.json is located) */ public static getPackageDir(): string { return path.resolve(__dirname, '../../'); } /** * Check if a file exists */ public static async fileExists(filePath: string): Promise { return smartfs.file(filePath).exists(); } /** * Check if a directory exists */ public static async directoryExists(dirPath: string): Promise { return smartfs.directory(dirPath).exists(); } /** * Read a JSON file and parse it */ public static readJsonSync(filePath: string): T { const content = fs.readFileSync(filePath, 'utf8'); return JSON.parse(content); } /** * List directory contents */ public static async listDirectory(dirPath: string) { return smartfs.directory(dirPath).list(); } /** * Remove a directory recursively */ public static async removeDirectory(dirPath: string): Promise { await fs.promises.rm(dirPath, { recursive: true }); } /** * Move/rename a file or directory */ public static async move(src: string, dest: string): Promise { await fs.promises.rename(src, dest); } /** * Remove an empty directory */ public static async removeEmptyDirectory(dirPath: string): Promise { await fs.promises.rmdir(dirPath); } }