├── README.md ├── package.json ├── .gitignore ├── tsconfig.json ├── index.ts └── bun.lock /README.md: -------------------------------------------------------------------------------- 1 | # floss 2 | file-system utilities for bun 3 | 4 | ## Installation 5 | ```bash 6 | bun add github:phillip-england/floss#0.0.2 7 | ``` -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "floss", 3 | "module": "index.ts", 4 | "type": "module", 5 | "devDependencies": { 6 | "@types/bun": "latest" 7 | }, 8 | "peerDependencies": { 9 | "typescript": "^5" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies (bun install) 2 | node_modules 3 | 4 | # output 5 | out 6 | dist 7 | *.tgz 8 | 9 | # code coverage 10 | coverage 11 | *.lcov 12 | 13 | # logs 14 | logs 15 | _.log 16 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 17 | 18 | # dotenv environment variable files 19 | .env 20 | .env.development.local 21 | .env.test.local 22 | .env.production.local 23 | .env.local 24 | 25 | # caches 26 | .eslintcache 27 | .cache 28 | *.tsbuildinfo 29 | 30 | # IntelliJ based IDEs 31 | .idea 32 | 33 | # Finder (MacOS) folder config 34 | .DS_Store 35 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // Environment setup & latest features 4 | "lib": ["ESNext"], 5 | "target": "ESNext", 6 | "module": "Preserve", 7 | "moduleDetection": "force", 8 | "jsx": "react-jsx", 9 | "allowJs": true, 10 | 11 | // Bundler mode 12 | "moduleResolution": "bundler", 13 | "allowImportingTsExtensions": true, 14 | "verbatimModuleSyntax": true, 15 | "noEmit": true, 16 | 17 | // Best practices 18 | "strict": true, 19 | "skipLibCheck": true, 20 | "noFallthroughCasesInSwitch": true, 21 | "noUncheckedIndexedAccess": true, 22 | "noImplicitOverride": true, 23 | 24 | // Some stricter flags (disabled by default) 25 | "noUnusedLocals": false, 26 | "noUnusedParameters": false, 27 | "noPropertyAccessFromIndexSignature": false 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { readdir } from 'fs/promises'; 3 | import { access, stat } from 'fs/promises'; 4 | import { join } from 'path'; 5 | import { rm } from 'fs/promises'; 6 | import type { BunFile } from 'bun'; 7 | 8 | export async function walkDir( 9 | dirPath: string, 10 | callback: (path: string, isDirectory: boolean) => void | Promise 11 | ) { 12 | await callback(dirPath, true); 13 | 14 | const files = await readdir(dirPath, { withFileTypes: true }) 15 | for (const file of files) { 16 | const path = join(dirPath, file.name); 17 | if (file.isDirectory()) { 18 | await callback(path, true); 19 | await walkDir(path, callback); 20 | } else { 21 | await callback(path, false); 22 | } 23 | } 24 | } 25 | 26 | export async function fileExists(path: string): Promise { 27 | try { 28 | await access(path); 29 | return true; 30 | } catch { 31 | return false; 32 | } 33 | } 34 | 35 | export async function dirExists(path: string): Promise { 36 | try { 37 | const stats = await stat(path); 38 | return stats.isDirectory(); 39 | } catch { 40 | return false; 41 | } 42 | } 43 | 44 | export async function rmdirIfExists(path: string) { 45 | if (await dirExists(path)) { 46 | await rm(path); 47 | } 48 | } 49 | 50 | export async function loadFile(...pathParts: string[]): Promise { 51 | let p = path.join(...pathParts) 52 | let file = Bun.file(p); 53 | return file 54 | } -------------------------------------------------------------------------------- /bun.lock: -------------------------------------------------------------------------------- 1 | { 2 | "lockfileVersion": 1, 3 | "workspaces": { 4 | "": { 5 | "name": "floss", 6 | "devDependencies": { 7 | "@types/bun": "latest", 8 | }, 9 | "peerDependencies": { 10 | "typescript": "^5", 11 | }, 12 | }, 13 | }, 14 | "packages": { 15 | "@types/bun": ["@types/bun@1.3.0", "", { "dependencies": { "bun-types": "1.3.0" } }, "sha512-+lAGCYjXjip2qY375xX/scJeVRmZ5cY0wyHYyCYxNcdEXrQ4AOe3gACgd4iQ8ksOslJtW4VNxBJ8llUwc3a6AA=="], 16 | 17 | "@types/node": ["@types/node@24.7.2", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-/NbVmcGTP+lj5oa4yiYxxeBjRivKQ5Ns1eSZeB99ExsEQ6rX5XYU1Zy/gGxY/ilqtD4Etx9mKyrPxZRetiahhA=="], 18 | 19 | "@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="], 20 | 21 | "bun-types": ["bun-types@1.3.0", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-u8X0thhx+yJ0KmkxuEo9HAtdfgCBaM/aI9K90VQcQioAmkVp3SG3FkwWGibUFz3WdXAdcsqOcbU40lK7tbHdkQ=="], 22 | 23 | "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], 24 | 25 | "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], 26 | 27 | "undici-types": ["undici-types@7.14.0", "", {}, "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA=="], 28 | } 29 | } 30 | --------------------------------------------------------------------------------