@auto-engineer/file-store 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-test.log +6 -11
- package/.turbo/turbo-type-check.log +1 -1
- package/CHANGELOG.md +6 -0
- package/dist/src/{LightningFileStore.d.ts → InMemoryFileStore.d.ts} +6 -10
- package/dist/src/InMemoryFileStore.d.ts.map +1 -0
- package/dist/src/InMemoryFileStore.js +60 -0
- package/dist/src/InMemoryFileStore.js.map +1 -0
- package/dist/src/index.d.ts +0 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +0 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/path.d.ts +0 -2
- package/dist/src/path.d.ts.map +1 -1
- package/dist/src/path.js +0 -13
- package/dist/src/path.js.map +1 -1
- package/dist/src/types.d.ts +0 -7
- package/dist/src/types.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -30
- package/src/InMemoryFileStore.ts +68 -0
- package/src/index.ts +0 -2
- package/src/path.ts +0 -14
- package/src/types.ts +0 -9
- package/tsconfig.json +1 -1
- package/dist/src/FileWatcher.d.ts +0 -27
- package/dist/src/FileWatcher.d.ts.map +0 -1
- package/dist/src/FileWatcher.js +0 -78
- package/dist/src/FileWatcher.js.map +0 -1
- package/dist/src/LightningFileStore.d.ts.map +0 -1
- package/dist/src/LightningFileStore.js +0 -105
- package/dist/src/LightningFileStore.js.map +0 -1
- package/dist/src/LightningFileStore.specs.d.ts +0 -2
- package/dist/src/LightningFileStore.specs.d.ts.map +0 -1
- package/dist/src/LightningFileStore.specs.js +0 -86
- package/dist/src/LightningFileStore.specs.js.map +0 -1
- package/dist/src/text-helpers.d.ts +0 -7
- package/dist/src/text-helpers.d.ts.map +0 -1
- package/dist/src/text-helpers.js +0 -9
- package/dist/src/text-helpers.js.map +0 -1
- package/src/FileWatcher.ts +0 -83
- package/src/LightningFileStore.specs.ts +0 -109
- package/src/LightningFileStore.ts +0 -126
- package/src/text-helpers.ts +0 -16
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
3
|
-
import 'fake-indexeddb/auto';
|
|
4
|
-
import { LightningFileStore } from './LightningFileStore';
|
|
5
|
-
|
|
6
|
-
const te = new TextEncoder();
|
|
7
|
-
const td = new TextDecoder();
|
|
8
|
-
|
|
9
|
-
const resetIDBs = async () =>
|
|
10
|
-
await new Promise<void>((res, rej) => {
|
|
11
|
-
const dbs = ['flowfs-test', 'flowfs-complex-test'];
|
|
12
|
-
let done = 0;
|
|
13
|
-
for (const name of dbs) {
|
|
14
|
-
const req = indexedDB.deleteDatabase(name);
|
|
15
|
-
req.onerror = () => rej(req.error);
|
|
16
|
-
req.onsuccess = () => {
|
|
17
|
-
done += 1;
|
|
18
|
-
if (done === dbs.length) res();
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
beforeEach(async () => {
|
|
24
|
-
await resetIDBs();
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
describe('LightningFS FileStore (basic ops)', () => {
|
|
28
|
-
it('writes and reads a file', async () => {
|
|
29
|
-
const fs = new LightningFileStore('flowfs-test');
|
|
30
|
-
|
|
31
|
-
await fs.write('/test.txt', te.encode('hello world'));
|
|
32
|
-
const buf = await fs.read('/test.txt');
|
|
33
|
-
|
|
34
|
-
expect(buf).not.toBeNull();
|
|
35
|
-
expect(td.decode(buf!)).toBe('hello world');
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('checks file existence', async () => {
|
|
39
|
-
const fs = new LightningFileStore('flowfs-test');
|
|
40
|
-
|
|
41
|
-
await fs.write('/exists.txt', te.encode('ok'));
|
|
42
|
-
|
|
43
|
-
expect(await fs.exists('/exists.txt')).toBe(true);
|
|
44
|
-
expect(await fs.exists('/missing.txt')).toBe(false);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('supports nested directories (mkdir -p style) for write/read', async () => {
|
|
48
|
-
const fs = new LightningFileStore('flowfs-test');
|
|
49
|
-
|
|
50
|
-
await fs.write('/nested/deep/file.txt', te.encode('nested content'));
|
|
51
|
-
const buf = await fs.read('/nested/deep/file.txt');
|
|
52
|
-
|
|
53
|
-
expect(buf).not.toBeNull();
|
|
54
|
-
expect(td.decode(buf!)).toBe('nested content');
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('lists directory contents via listTree()', async () => {
|
|
58
|
-
const fs = new LightningFileStore('flowfs-test');
|
|
59
|
-
|
|
60
|
-
await fs.write('/a.txt', te.encode('a'));
|
|
61
|
-
await fs.write('/dir/b.txt', te.encode('b'));
|
|
62
|
-
|
|
63
|
-
const tree = await fs.listTree('/');
|
|
64
|
-
|
|
65
|
-
const paths = tree.map((e) => e.path).sort();
|
|
66
|
-
expect(paths).toContain('/');
|
|
67
|
-
expect(paths).toContain('/a.txt');
|
|
68
|
-
expect(paths).toContain('/dir');
|
|
69
|
-
expect(paths).toContain('/dir/b.txt');
|
|
70
|
-
|
|
71
|
-
const root = tree.find((e) => e.path === '/');
|
|
72
|
-
const dir = tree.find((e) => e.path === '/dir');
|
|
73
|
-
const file = tree.find((e) => e.path === '/a.txt');
|
|
74
|
-
|
|
75
|
-
expect(root?.type).toBe('dir');
|
|
76
|
-
expect(dir?.type).toBe('dir');
|
|
77
|
-
expect(file?.type).toBe('file');
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
describe('LightningFS FileStore (complex structure)', () => {
|
|
82
|
-
it('creates and verifies a multi-level project layout', async () => {
|
|
83
|
-
const fs = new LightningFileStore('flowfs-complex-test');
|
|
84
|
-
|
|
85
|
-
await fs.write('/src/flows/items.flow.ts', te.encode('items flow'));
|
|
86
|
-
await fs.write('/src/flows/orders.flow.ts', te.encode('orders flow'));
|
|
87
|
-
await fs.write('/src/integrations/user.integration.ts', te.encode('user integration'));
|
|
88
|
-
await fs.write('/config/settings.json', te.encode('{"key":"value"}'));
|
|
89
|
-
|
|
90
|
-
expect(await fs.exists('/src/flows/items.flow.ts')).toBe(true);
|
|
91
|
-
expect(await fs.exists('/src/flows/orders.flow.ts')).toBe(true);
|
|
92
|
-
expect(await fs.exists('/src/integrations/user.integration.ts')).toBe(true);
|
|
93
|
-
expect(await fs.exists('/config/settings.json')).toBe(true);
|
|
94
|
-
|
|
95
|
-
const tree = await fs.listTree('/src');
|
|
96
|
-
const paths = tree.map((e) => e.path);
|
|
97
|
-
|
|
98
|
-
expect(paths).toContain('/src');
|
|
99
|
-
expect(paths).toContain('/src/flows');
|
|
100
|
-
expect(paths).toContain('/src/integrations');
|
|
101
|
-
expect(paths).toContain('/src/flows/items.flow.ts');
|
|
102
|
-
expect(paths).toContain('/src/flows/orders.flow.ts');
|
|
103
|
-
|
|
104
|
-
// verify content
|
|
105
|
-
const itemsBuf = await fs.read('/src/flows/items.flow.ts');
|
|
106
|
-
expect(itemsBuf).not.toBeNull();
|
|
107
|
-
expect(td.decode(itemsBuf!)).toBe('items flow');
|
|
108
|
-
});
|
|
109
|
-
});
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import LightningFS from '@isomorphic-git/lightning-fs';
|
|
2
|
-
import type { IFileStore } from './types';
|
|
3
|
-
import { dirname } from './path';
|
|
4
|
-
|
|
5
|
-
interface LightningFSStats {
|
|
6
|
-
isDirectory(): boolean;
|
|
7
|
-
size: number;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
interface LightningFSPromises {
|
|
11
|
-
writeFile(path: string, data: Uint8Array): Promise<void>;
|
|
12
|
-
readFile(path: string): Promise<Uint8Array>;
|
|
13
|
-
stat(path: string): Promise<LightningFSStats>;
|
|
14
|
-
readdir(path: string): Promise<string[]>;
|
|
15
|
-
mkdir(path: string): Promise<void>;
|
|
16
|
-
unlink(path: string): Promise<void>;
|
|
17
|
-
rmdir(path: string): Promise<void>;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
interface LightningFSInstance {
|
|
21
|
-
promises: LightningFSPromises;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export class LightningFileStore implements IFileStore {
|
|
25
|
-
private fs: LightningFSInstance;
|
|
26
|
-
private pfs: LightningFSPromises;
|
|
27
|
-
|
|
28
|
-
constructor(name = 'pocfs') {
|
|
29
|
-
this.fs = new LightningFS(name) as LightningFSInstance;
|
|
30
|
-
this.pfs = this.fs.promises;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async write(path: string, data: Uint8Array): Promise<void> {
|
|
34
|
-
await this.mkdirp(dirname(path));
|
|
35
|
-
await this.pfs.writeFile(path, data);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async read(path: string): Promise<Uint8Array | null> {
|
|
39
|
-
try {
|
|
40
|
-
return await this.pfs.readFile(path);
|
|
41
|
-
} catch {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async exists(path: string): Promise<boolean> {
|
|
47
|
-
return await this.pfs
|
|
48
|
-
.stat(path)
|
|
49
|
-
.then(() => true)
|
|
50
|
-
.catch(() => false);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async listTree(root: string = '/'): Promise<Array<{ path: string; type: 'file' | 'dir'; size: number }>> {
|
|
54
|
-
const out: Array<{ path: string; type: 'file' | 'dir'; size: number }> = [];
|
|
55
|
-
const walk = async (p: string) => {
|
|
56
|
-
let st: LightningFSStats | null = null;
|
|
57
|
-
try {
|
|
58
|
-
st = await this.pfs.stat(p);
|
|
59
|
-
} catch {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (st !== null && st.isDirectory()) {
|
|
64
|
-
out.push({ path: p, type: 'dir', size: 0 });
|
|
65
|
-
let entries: string[] = [];
|
|
66
|
-
try {
|
|
67
|
-
entries = await this.pfs.readdir(p);
|
|
68
|
-
} catch {
|
|
69
|
-
/* ignore */
|
|
70
|
-
}
|
|
71
|
-
for (const name of entries) {
|
|
72
|
-
const child = p === '/' ? `/${name}` : `${p}/${name}`;
|
|
73
|
-
await walk(child);
|
|
74
|
-
}
|
|
75
|
-
} else {
|
|
76
|
-
out.push({ path: p, type: 'file', size: st?.size ?? 0 });
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
await walk(root);
|
|
80
|
-
out.sort((a, b) => (a.type === b.type ? a.path.localeCompare(b.path) : a.type === 'dir' ? -1 : 1));
|
|
81
|
-
return out;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async remove(path: string): Promise<void> {
|
|
85
|
-
if (!path) return;
|
|
86
|
-
try {
|
|
87
|
-
const st = await this.pfs.stat(path);
|
|
88
|
-
if (st.isDirectory()) {
|
|
89
|
-
await this.removeDirectory(path);
|
|
90
|
-
} else {
|
|
91
|
-
await this.pfs.unlink(path);
|
|
92
|
-
}
|
|
93
|
-
} catch (err: unknown) {
|
|
94
|
-
if (this.isFileNotFoundError(err)) return;
|
|
95
|
-
throw err;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
private async removeDirectory(path: string): Promise<void> {
|
|
100
|
-
const entries = await this.pfs.readdir(path).catch(() => []);
|
|
101
|
-
for (const name of entries) {
|
|
102
|
-
const child = path === '/' ? `/${name}` : `${path}/${name}`;
|
|
103
|
-
await this.remove(child);
|
|
104
|
-
}
|
|
105
|
-
await this.pfs.rmdir(path);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
private isFileNotFoundError(err: unknown): boolean {
|
|
109
|
-
if (err instanceof Error && 'code' in err && err.code === 'ENOENT') return true;
|
|
110
|
-
return err === null || err === undefined;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
private async mkdirp(path: string): Promise<void> {
|
|
114
|
-
if (!path || path === '/') return;
|
|
115
|
-
const parts = path.split('/').filter(Boolean);
|
|
116
|
-
let cur = '';
|
|
117
|
-
for (const part of parts) {
|
|
118
|
-
cur += '/' + part;
|
|
119
|
-
const exists = await this.pfs
|
|
120
|
-
.stat(cur)
|
|
121
|
-
.then(() => true)
|
|
122
|
-
.catch(() => false);
|
|
123
|
-
if (!exists) await this.pfs.mkdir(cur);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
package/src/text-helpers.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export async function readText(
|
|
2
|
-
fs: { read(path: string): Promise<Uint8Array | null> },
|
|
3
|
-
path: string,
|
|
4
|
-
): Promise<string | null> {
|
|
5
|
-
const buf = await fs.read(path);
|
|
6
|
-
return buf ? new TextDecoder().decode(buf) : null;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export async function writeText(
|
|
10
|
-
fs: { write(path: string, data: Uint8Array): Promise<void> },
|
|
11
|
-
path: string,
|
|
12
|
-
text: string,
|
|
13
|
-
): Promise<void> {
|
|
14
|
-
const buf = new TextEncoder().encode(text);
|
|
15
|
-
await fs.write(path, buf);
|
|
16
|
-
}
|