filesystem.ts 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. import { exists } from "fs/promises"
  2. import { dirname, join, relative } from "path"
  3. export namespace Filesystem {
  4. export function overlaps(a: string, b: string) {
  5. const relA = relative(a, b)
  6. const relB = relative(b, a)
  7. return !relA || !relA.startsWith("..") || !relB || !relB.startsWith("..")
  8. }
  9. export function contains(parent: string, child: string) {
  10. return !relative(parent, child).startsWith("..")
  11. }
  12. export async function findUp(target: string, start: string, stop?: string) {
  13. let current = start
  14. const result = []
  15. while (true) {
  16. const search = join(current, target)
  17. if (await exists(search)) result.push(search)
  18. if (stop === current) break
  19. const parent = dirname(current)
  20. if (parent === current) break
  21. current = parent
  22. }
  23. return result
  24. }
  25. export async function* up(options: { targets: string[]; start: string; stop?: string }) {
  26. const { targets, start, stop } = options
  27. let current = start
  28. while (true) {
  29. for (const target of targets) {
  30. const search = join(current, target)
  31. if (await exists(search)) yield search
  32. }
  33. if (stop === current) break
  34. const parent = dirname(current)
  35. if (parent === current) break
  36. current = parent
  37. }
  38. }
  39. export async function globUp(pattern: string, start: string, stop?: string) {
  40. let current = start
  41. const result = []
  42. while (true) {
  43. try {
  44. const glob = new Bun.Glob(pattern)
  45. for await (const match of glob.scan({
  46. cwd: current,
  47. absolute: true,
  48. onlyFiles: true,
  49. followSymlinks: true,
  50. dot: true,
  51. })) {
  52. result.push(match)
  53. }
  54. } catch {
  55. // Skip invalid glob patterns
  56. }
  57. if (stop === current) break
  58. const parent = dirname(current)
  59. if (parent === current) break
  60. current = parent
  61. }
  62. return result
  63. }
  64. }