Skip to content

Commit f1a2e71

Browse files
authored
Merge pull request #4 from constructive-io/devin/1766963231-lean-adapter
Refactor ZenFsAdapter to be lean and slick
2 parents 57cb93f + 1d8e64e commit f1a2e71

1 file changed

Lines changed: 39 additions & 178 deletions

File tree

Lines changed: 39 additions & 178 deletions
Original file line numberDiff line numberDiff line change
@@ -1,185 +1,46 @@
1-
import { fs as zenfs } from '@zenfs/core';
2-
import * as path from 'path';
3-
4-
export interface FsStat {
5-
isFile: boolean;
6-
isDirectory: boolean;
7-
isSymbolicLink: boolean;
8-
mode: number;
9-
size: number;
10-
mtime: Date;
11-
}
12-
13-
export interface MkdirOptions {
14-
recursive?: boolean;
15-
}
16-
17-
export interface RmOptions {
18-
recursive?: boolean;
19-
force?: boolean;
20-
}
21-
22-
export interface CpOptions {
23-
recursive?: boolean;
24-
}
25-
26-
export interface ReadFileOptions {
27-
encoding?: string | null;
28-
}
29-
30-
export interface WriteFileOptions {
31-
encoding?: string;
32-
}
33-
34-
export type FileContent = string | Uint8Array;
1+
import { fs } from '@zenfs/core';
2+
import { posix } from 'path';
3+
4+
type StatLike = { isFile(): boolean; isDirectory(): boolean; isSymbolicLink(): boolean; mode: number | bigint; size: number | bigint; mtime: Date };
5+
const toStat = (s: StatLike) => ({
6+
isFile: s.isFile(),
7+
isDirectory: s.isDirectory(),
8+
isSymbolicLink: s.isSymbolicLink(),
9+
mode: Number(s.mode),
10+
size: Number(s.size),
11+
mtime: s.mtime,
12+
});
3513

3614
export class ZenFsAdapter {
37-
async readFile(filePath: string, options?: ReadFileOptions | string): Promise<string> {
38-
const encoding = typeof options === 'string' ? options : options?.encoding ?? 'utf-8';
39-
return zenfs.readFileSync(filePath, encoding as BufferEncoding);
40-
}
41-
42-
async readFileBuffer(filePath: string): Promise<Uint8Array> {
43-
const buffer = zenfs.readFileSync(filePath);
44-
if (typeof buffer === 'string') {
45-
return new TextEncoder().encode(buffer);
46-
}
47-
return new Uint8Array(buffer);
48-
}
49-
50-
async writeFile(filePath: string, content: FileContent, options?: WriteFileOptions | string): Promise<void> {
51-
this.ensureParentDirs(filePath);
52-
zenfs.writeFileSync(filePath, content);
53-
}
54-
55-
async appendFile(filePath: string, content: FileContent, options?: WriteFileOptions | string): Promise<void> {
56-
this.ensureParentDirs(filePath);
57-
zenfs.appendFileSync(filePath, content);
58-
}
59-
60-
async exists(filePath: string): Promise<boolean> {
61-
return zenfs.existsSync(filePath);
62-
}
63-
64-
async stat(filePath: string): Promise<FsStat> {
65-
const stats = zenfs.statSync(filePath);
66-
return {
67-
isFile: stats.isFile(),
68-
isDirectory: stats.isDirectory(),
69-
isSymbolicLink: stats.isSymbolicLink(),
70-
mode: stats.mode,
71-
size: stats.size,
72-
mtime: stats.mtime,
73-
};
74-
}
75-
76-
async lstat(filePath: string): Promise<FsStat> {
77-
const stats = zenfs.lstatSync(filePath);
78-
return {
79-
isFile: stats.isFile(),
80-
isDirectory: stats.isDirectory(),
81-
isSymbolicLink: stats.isSymbolicLink(),
82-
mode: stats.mode,
83-
size: stats.size,
84-
mtime: stats.mtime,
85-
};
86-
}
87-
88-
async mkdir(dirPath: string, options?: MkdirOptions): Promise<void> {
89-
zenfs.mkdirSync(dirPath, { recursive: options?.recursive });
90-
}
91-
92-
async readdir(dirPath: string): Promise<string[]> {
93-
return zenfs.readdirSync(dirPath) as string[];
94-
}
95-
96-
async rm(filePath: string, options?: RmOptions): Promise<void> {
97-
try {
98-
zenfs.rmSync(filePath, { recursive: options?.recursive, force: options?.force });
99-
} catch (e) {
100-
if (!options?.force) throw e;
101-
}
102-
}
103-
104-
async cp(src: string, dest: string, options?: CpOptions): Promise<void> {
105-
const srcStat = zenfs.statSync(src);
106-
if (srcStat.isDirectory()) {
107-
if (!options?.recursive) {
108-
throw new Error(`EISDIR: is a directory, cp '${src}'`);
109-
}
110-
zenfs.mkdirSync(dest, { recursive: true });
111-
const entries = zenfs.readdirSync(src) as string[];
112-
for (const entry of entries) {
113-
await this.cp(path.posix.join(src, entry), path.posix.join(dest, entry), options);
114-
}
115-
} else {
116-
this.ensureParentDirs(dest);
117-
zenfs.copyFileSync(src, dest);
118-
}
119-
}
120-
121-
async mv(src: string, dest: string): Promise<void> {
122-
zenfs.renameSync(src, dest);
123-
}
124-
125-
resolvePath(base: string, filePath: string): string {
126-
if (filePath.startsWith('/')) {
127-
return path.posix.normalize(filePath);
128-
}
129-
return path.posix.normalize(path.posix.join(base, filePath));
130-
}
15+
readFile = (p: string) => fs.promises.readFile(p, 'utf-8');
16+
readFileBuffer = async (p: string) => new Uint8Array(await fs.promises.readFile(p));
17+
writeFile = (p: string, c: string | Uint8Array) => fs.promises.writeFile(p, c);
18+
appendFile = (p: string, c: string | Uint8Array) => fs.promises.appendFile(p, c);
19+
exists = (p: string) => fs.promises.exists(p);
20+
mkdir = async (p: string, o?: { recursive?: boolean }) => { await fs.promises.mkdir(p, o); };
21+
readdir = (p: string) => fs.promises.readdir(p) as Promise<string[]>;
22+
rm = (p: string, o?: { recursive?: boolean; force?: boolean }) => fs.promises.rm(p, o);
23+
cp = (s: string, d: string, o?: { recursive?: boolean }) => fs.promises.cp(s, d, o);
24+
mv = async (s: string, d: string) => { await fs.promises.rename(s, d); };
25+
chmod = (p: string, m: number) => fs.promises.chmod(p, m);
26+
symlink = (t: string, l: string) => fs.promises.symlink(t, l);
27+
link = (e: string, n: string) => fs.promises.link(e, n);
28+
readlink = (p: string) => fs.promises.readlink(p);
29+
stat = async (p: string) => toStat(await fs.promises.stat(p));
30+
lstat = async (p: string) => toStat(await fs.promises.lstat(p));
31+
resolvePath = (base: string, p: string) => posix.normalize(p.startsWith('/') ? p : posix.join(base, p));
13132

13233
getAllPaths(): string[] {
133-
const paths: string[] = [];
134-
this.walkDir('/', paths);
135-
return paths;
136-
}
137-
138-
private walkDir(dir: string, paths: string[]): void {
139-
paths.push(dir);
140-
try {
141-
const entries = zenfs.readdirSync(dir) as string[];
142-
for (const entry of entries) {
143-
const fullPath = dir === '/' ? `/${entry}` : `${dir}/${entry}`;
144-
try {
145-
const stats = zenfs.lstatSync(fullPath);
146-
if (stats.isDirectory()) {
147-
this.walkDir(fullPath, paths);
148-
} else {
149-
paths.push(fullPath);
150-
}
151-
} catch {
152-
paths.push(fullPath);
34+
const walk = (dir: string): string[] => {
35+
const paths = [dir];
36+
try {
37+
for (const e of fs.readdirSync(dir)) {
38+
const full = dir === '/' ? `/${e}` : `${dir}/${e}`;
39+
paths.push(...(fs.lstatSync(full).isDirectory() ? walk(full) : [full]));
15340
}
154-
}
155-
} catch {
156-
// Directory not readable, skip
157-
}
158-
}
159-
160-
async chmod(filePath: string, mode: number): Promise<void> {
161-
zenfs.chmodSync(filePath, mode);
162-
}
163-
164-
async symlink(target: string, linkPath: string): Promise<void> {
165-
this.ensureParentDirs(linkPath);
166-
zenfs.symlinkSync(target, linkPath);
167-
}
168-
169-
async link(existingPath: string, newPath: string): Promise<void> {
170-
this.ensureParentDirs(newPath);
171-
zenfs.linkSync(existingPath, newPath);
172-
}
173-
174-
async readlink(linkPath: string): Promise<string> {
175-
const result = zenfs.readlinkSync(linkPath);
176-
return typeof result === 'string' ? result : result.toString('utf-8');
177-
}
178-
179-
private ensureParentDirs(filePath: string): void {
180-
const dir = path.posix.dirname(filePath);
181-
if (dir && dir !== '/' && !zenfs.existsSync(dir)) {
182-
zenfs.mkdirSync(dir, { recursive: true });
183-
}
41+
} catch { /* skip unreadable */ }
42+
return paths;
43+
};
44+
return walk('/');
18445
}
18546
}

0 commit comments

Comments
 (0)