BREAKING(structure): modernize internal structure and support unpacking

This commit is contained in:
2025-12-13 22:59:58 +00:00
parent 4ebc37fa5a
commit e5fcbb9a09
19 changed files with 1605 additions and 1318 deletions

View File

@@ -0,0 +1,144 @@
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<string[]> {
// 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<boolean> {
return smartfs.file(filePath).exists();
}
/**
* Check if a directory exists
*/
public static async directoryExists(dirPath: string): Promise<boolean> {
return smartfs.directory(dirPath).exists();
}
/**
* Read a JSON file and parse it
*/
public static readJsonSync<T = any>(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<void> {
await fs.promises.rm(dirPath, { recursive: true });
}
/**
* Move/rename a file or directory
*/
public static async move(src: string, dest: string): Promise<void> {
await fs.promises.rename(src, dest);
}
/**
* Remove an empty directory
*/
public static async removeEmptyDirectory(dirPath: string): Promise<void> {
await fs.promises.rmdir(dirPath);
}
}