147 lines
3.6 KiB
TypeScript
147 lines
3.6 KiB
TypeScript
import { join, resolve, basename, dirname, extname } from 'path'
|
|
import {
|
|
readdirSync,
|
|
mkdirSync,
|
|
rmdirSync,
|
|
readFileSync,
|
|
writeFileSync,
|
|
appendFileSync,
|
|
rmSync,
|
|
copyFileSync,
|
|
statSync,
|
|
lstatSync,
|
|
chmodSync,
|
|
symlinkSync,
|
|
readlinkSync,
|
|
watch,
|
|
} from 'fs'
|
|
|
|
export const fs = {
|
|
// Directory operations
|
|
ls: (path: string) => readdirSync(path),
|
|
mkdir: (path: string) => mkdirSync(path, { recursive: true }),
|
|
rmdir: (path: string) =>
|
|
rmdirSync(path === '/' || path === '' ? '/tmp/*' : path, { recursive: true }),
|
|
pwd: () => process.cwd(),
|
|
cd: (path: string) => process.chdir(path),
|
|
|
|
// Reading
|
|
read: (path: string) => readFileSync(path, 'utf-8'),
|
|
cat: (path: string) => {}, // added below
|
|
'read-bytes': (path: string) => [...readFileSync(path)],
|
|
|
|
// Writing
|
|
write: (path: string, content: string) => writeFileSync(path, content),
|
|
append: (path: string, content: string) => appendFileSync(path, content),
|
|
|
|
// File operations
|
|
delete: (path: string) => rmSync(path),
|
|
rm: (path: string) => {}, // added below
|
|
copy: (from: string, to: string) => copyFileSync(from, to),
|
|
move: (from: string, to: string) => {
|
|
fs.copy(from, to)
|
|
fs.rm(from)
|
|
},
|
|
mv: (from: string, to: string) => {}, // added below
|
|
|
|
// Path operations
|
|
basename: (path: string) => basename(path),
|
|
dirname: (path: string) => dirname(path),
|
|
extname: (path: string) => extname(path),
|
|
join: (...paths: string[]) => join(...paths),
|
|
resolve: (...paths: string[]) => resolve(...paths),
|
|
|
|
// File info
|
|
stat: (path: string) => {
|
|
try {
|
|
const stats = statSync(path)
|
|
const record = Object.fromEntries(Object.entries(stats))
|
|
record['atime'] = record['atimeMs']
|
|
record['ctime'] = record['ctimeMs']
|
|
record['mtime'] = record['mtimeMs']
|
|
|
|
delete record['atimeMs']
|
|
delete record['ctimeMs']
|
|
delete record['mtimeMs']
|
|
|
|
return record
|
|
} catch {
|
|
return {}
|
|
}
|
|
},
|
|
'exists?': (path: string) => {
|
|
try {
|
|
statSync(path)
|
|
return true
|
|
} catch {
|
|
return false
|
|
}
|
|
},
|
|
'file?': (path: string) => {
|
|
try {
|
|
return statSync(path).isFile()
|
|
} catch {
|
|
return false
|
|
}
|
|
},
|
|
'dir?': (path: string) => {
|
|
try {
|
|
return statSync(path).isDirectory()
|
|
} catch {
|
|
return false
|
|
}
|
|
},
|
|
'symlink?': (path: string) => {
|
|
try {
|
|
return lstatSync(path).isSymbolicLink()
|
|
} catch {
|
|
return false
|
|
}
|
|
},
|
|
'exec?': (path: string) => {
|
|
try {
|
|
const stats = statSync(path)
|
|
return !!(stats.mode & 0o111)
|
|
} catch {
|
|
return false
|
|
}
|
|
},
|
|
size: (path: string) => {
|
|
try {
|
|
return statSync(path).size
|
|
} catch {
|
|
return 0
|
|
}
|
|
},
|
|
|
|
// Permissions
|
|
chmod: (path: string, mode: number | string) => {
|
|
const numMode = typeof mode === 'string' ? parseInt(mode, 8) : mode
|
|
chmodSync(path, numMode)
|
|
},
|
|
|
|
// Symlinks
|
|
symlink: (target: string, path: string) => symlinkSync(target, path),
|
|
readlink: (path: string) => readlinkSync(path, 'utf-8'),
|
|
|
|
// Other
|
|
glob: (pattern: string) => {
|
|
const dir = pattern.substring(0, pattern.lastIndexOf('/'))
|
|
const match = pattern.substring(pattern.lastIndexOf('/') + 1)
|
|
|
|
if (!match.includes('*')) throw new Error('only * patterns supported')
|
|
|
|
const ext = match.split('*').pop()!
|
|
return readdirSync(dir)
|
|
.filter((f) => f.endsWith(ext))
|
|
.map((f) => join(dir, f))
|
|
},
|
|
|
|
watch: (path: string, callback: Function) =>
|
|
watch(path, (event, filename) => callback(event, filename)),
|
|
}
|
|
;(fs as any).cat = fs.read
|
|
;(fs as any).mv = fs.move
|
|
;(fs as any).cp = fs.copy
|
|
;(fs as any).rm = fs.delete
|