shrimp/src/prelude/fs.ts

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