Skip to content

fs

File system utilities, providing file operations, directory scanning, safe writing, change detection, report path resolution, file mapping, and batch deletion.

Import

typescript
// Submodule import (recommended)
import { checkSourceExists, copySourceToTarget, writeFileContent, scanDirectory, writeJsonReport, writeFileSyncSafely, shouldUpdateFileContent, resolveReportPath, scanAndMapFiles, deleteFiles } from '@meng-xi/vite-plugin/common/fs'
import type { CopyOptions, CopyResult, ScannedFile, ScanDirectoryOptions } from '@meng-xi/vite-plugin/common/fs'

// Barrel import
import { checkSourceExists, copySourceToTarget, writeFileContent, scanDirectory, writeJsonReport, writeFileSyncSafely, shouldUpdateFileContent, resolveReportPath, scanAndMapFiles, deleteFiles } from '@meng-xi/vite-plugin/common'
import type { CopyOptions, CopyResult, ScannedFile, ScanDirectoryOptions } from '@meng-xi/vite-plugin/common'

Type Exports

CopyOptions

Copy operation options interface.

typescript
interface CopyOptions {
	recursive: boolean // Whether to recursively copy subdirectories
	overwrite: boolean // Whether to overwrite existing files
	incremental?: boolean // Whether to only copy modified files (default false)
	parallelLimit?: number // Concurrency limit (default 10)
	skipEmptyDirs?: boolean // Whether to skip empty directories
}

CopyResult

Copy result interface.

typescript
interface CopyResult {
	copiedFiles: number // Number of copied files
	skippedFiles: number // Number of skipped files
	copiedDirs: number // Number of copied directories
	executionTime: number // Execution time in milliseconds
}

checkSourceExists

Check if source file exists, throw an error if not found.

typescript
async function checkSourceExists(sourcePath: string): Promise<void>

Parameters

ParameterTypeDescription
sourcePathstringSource path

Example

typescript
await checkSourceExists('/path/to/file')
// Throws if not found: Error: 复制文件失败:源文件不存在 - /path/to/file

copySourceToTarget

Copy files or directories to target location.

typescript
async function copySourceToTarget(sourcePath: string, targetPath: string, options: CopyOptions): Promise<CopyResult>

Parameters

ParameterTypeDescription
sourcePathstringSource path
targetPathstringTarget path
optionsCopyOptionsCopy options

CopyOptions

PropertyTypeDefaultDescription
recursiveboolean-Recursively copy subdirectories
overwriteboolean-Overwrite existing files
incrementalbooleanfalseOnly copy modified files
parallelLimitnumber10Concurrency limit

CopyResult

PropertyTypeDescription
copiedFilesnumberNumber of copied files
skippedFilesnumberNumber of skipped files
copiedDirsnumberNumber of copied dirs
executionTimenumberExecution time (ms)

Example

typescript
const result = await copySourceToTarget('src/assets', 'dist/assets', {
	recursive: true,
	overwrite: true,
	incremental: true,
	parallelLimit: 10
})

console.log(result)
// { copiedFiles: 10, skippedFiles: 2, copiedDirs: 3, executionTime: 150 }

writeFileContent

Write content to a file.

typescript
async function writeFileContent(filePath: string, content: string): Promise<void>

Parameters

ParameterTypeDescription
filePathstringFile path
contentstringFile content

Example

typescript
await writeFileContent('/path/to/file.txt', 'Hello World')

scanDirectory

Recursively scan a directory and collect file information.

typescript
async function scanDirectory(dirPath: string, options?: ScanDirectoryOptions): Promise<ScannedFile[]>

Parameters

ParameterTypeDefaultDescription
dirPathstring-Directory path
optionsScanDirectoryOptions{}Scan options

ScanDirectoryOptions

PropertyTypeDefaultDescription
includeExtensionsstring[][]File extensions to include, empty for all
excludePatternsstring[][]Path patterns to exclude
filter(filePath: string, extension: string, size: number) => boolean-Custom file filter function

ScannedFile

PropertyTypeDescription
filePathstringAbsolute file path
sizenumberFile size in bytes
extensionstringFile extension (lowercase, with dot)

Returns

Promise<ScannedFile[]> - List of file information

Example

typescript
// Scan all .js files
const jsFiles = await scanDirectory('dist', { includeExtensions: ['.js'] })

// Exclude node_modules
const files = await scanDirectory('dist', { excludePatterns: ['node_modules'] })

// Custom filter
const largeFiles = await scanDirectory('dist', {
	filter: (filePath, ext, size) => size > 1024
})

writeJsonReport

Write data to a JSON file.

typescript
async function writeJsonReport(filePath: string, data: object, indent?: number): Promise<void>

Parameters

ParameterTypeDefaultDescription
filePathstring-Output file path
dataobject-Data object to serialize
indentnumber2JSON indentation spaces

Example

typescript
await writeJsonReport('dist/report.json', { timestamp: Date.now(), stats: [] })
await writeJsonReport('dist/report.json', data, 4)

writeFileSyncSafely

Synchronously write file content, automatically creating non-existent directories.

typescript
function writeFileSyncSafely(filePath: string, content: string): void

Parameters

ParameterTypeDescription
filePathstringFile path
contentstringFile content

Notes

  • Synchronously writes file, automatically creates target directories recursively if they don't exist
  • Suitable for scenarios requiring synchronous writes in build hooks (e.g., transform hook)
  • Throws NodeJS.ErrnoException when file write fails (e.g., insufficient permissions)

Example

typescript
writeFileSyncSafely('/project/src/auto-imports.d.ts', 'declare global { ... }')

shouldUpdateFileContent

Check if file content needs to be updated (synchronous version).

typescript
function shouldUpdateFileContent(filePath: string, newContent: string): boolean

Parameters

ParameterTypeDescription
filePathstringFile path
newContentstringNewly generated file content

Returns

boolean - Returns true if update is needed, false otherwise

Notes

  • Compares existing file content with newly generated content, only needs to write when content has changed
  • Reduces unnecessary file IO operations
  • Returns true when file doesn't exist

Example

typescript
if (shouldUpdateFileContent('/project/src/auto-imports.d.ts', newContent)) {
	writeFileSyncSafely('/project/src/auto-imports.d.ts', newContent)
}

resolveReportPath

Resolve report output path.

typescript
function resolveReportPath(outDir: string, reportPath: string | false): string | null

Parameters

ParameterTypeDescription
outDirstringBuild output directory path
reportPathstring | falseReport file path, false to skip report generation

Returns

string | null - Resolved absolute path, returns null when reportPath is false

Notes

  • When reportPath is a relative path, it is resolved relative to outDir
  • When reportPath is an absolute path, it is used directly
  • When reportPath is false, returns null

Example

typescript
resolveReportPath('dist', 'report.json')   // 'dist/report.json'
resolveReportPath('dist', '/tmp/r.json')    // '/tmp/r.json'
resolveReportPath('dist', false)            // null

scanAndMapFiles

Scan a directory and build a file path mapping table for quick file lookup.

typescript
async function scanAndMapFiles(
  dirPath: string,
  options?: ScanDirectoryOptions
): Promise<Map<string, ScannedFile>>

Parameters

ParameterTypeDefaultDescription
dirPathstring-Directory path
optionsScanDirectoryOptions{}Scan options (same as scanDirectory)

Returns

Promise<Map<string, ScannedFile>> - Map with file relative path as key and file info as value

Notes

  • Built on scanDirectory, converts scan results to a Map structure for O(1) lookup
  • Keys are normalized relative paths (using forward slashes) relative to dirPath
  • Suitable for scenarios requiring quick file existence checks or file info retrieval

Example

typescript
// Build file mapping table
const fileMap = await scanAndMapFiles('dist')

// Check if file exists
if (fileMap.has('assets/index.js')) {
	const file = fileMap.get('assets/index.js')!
	console.log(`File size: ${file.size} bytes`)
}

// Use with filter conditions
const jsFileMap = await scanAndMapFiles('dist', { includeExtensions: ['.js'] })

deleteFiles

Batch delete a list of files, ignoring non-existent files.

typescript
async function deleteFiles(files: string[]): Promise<{ deleted: number; skipped: number }>

Parameters

ParameterTypeDescription
filesstring[]List of file paths to delete

Returns

Promise<{ deleted: number; skipped: number }> - Deletion result statistics

PropertyTypeDescription
deletednumberNumber of files successfully deleted
skippednumberNumber of files skipped (not found or failed)

Notes

  • Concurrently deletes files to improve batch operation efficiency
  • Skips non-existent files without throwing exceptions
  • Skips individual file deletion failures and continues processing other files

Example

typescript
// Batch delete files
const result = await deleteFiles([
	'dist/old-file.js',
	'dist/old-file.css',
	'dist/temp.txt'
])

console.log(`Deleted ${result.deleted}, skipped ${result.skipped}`)

Released under the MIT License.