Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit3ee2531

Browse files
authored
Merge pull request#1138 from streamich/copilot/fix-1137
feat: implement fs.openAsBlob method
2 parents2d5d369 +b355f20 commit3ee2531

File tree

4 files changed

+530
-282
lines changed

4 files changed

+530
-282
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import{of}from'../../../thingies';
2+
import{memfs}from'../../../';
3+
4+
describe('.openAsBlob()',()=>{
5+
it('can read a text file as blob',async()=>{
6+
const{ fs}=memfs({'/dir/test.txt':'Hello, World!'});
7+
constblob=awaitfs.openAsBlob('/dir/test.txt');
8+
expect(blob).toBeInstanceOf(Blob);
9+
expect(blob.size).toBe(13);
10+
expect(blob.type).toBe('');
11+
12+
consttext=awaitblob.text();
13+
expect(text).toBe('Hello, World!');
14+
});
15+
16+
it('can read a binary file as blob',async()=>{
17+
constbinaryData=Buffer.from([0x89,0x50,0x4e,0x47]);// PNG header
18+
const{ fs}=memfs({'/image.png':binaryData});
19+
constblob=awaitfs.openAsBlob('/image.png');
20+
expect(blob).toBeInstanceOf(Blob);
21+
expect(blob.size).toBe(4);
22+
23+
constarrayBuffer=awaitblob.arrayBuffer();
24+
constview=newUint8Array(arrayBuffer);
25+
expect(Array.from(view)).toEqual([0x89,0x50,0x4e,0x47]);
26+
});
27+
28+
it('can specify a mime type',async()=>{
29+
const{ fs}=memfs({'/data.json':'{"key": "value"}'});
30+
constblob=awaitfs.openAsBlob('/data.json',{type:'application/json'});
31+
expect(blob).toBeInstanceOf(Blob);
32+
expect(blob.type).toBe('application/json');
33+
34+
consttext=awaitblob.text();
35+
expect(text).toBe('{"key": "value"}');
36+
});
37+
38+
it('handles empty files',async()=>{
39+
const{ fs}=memfs({'/empty.txt':''});
40+
constblob=awaitfs.openAsBlob('/empty.txt');
41+
expect(blob).toBeInstanceOf(Blob);
42+
expect(blob.size).toBe(0);
43+
44+
consttext=awaitblob.text();
45+
expect(text).toBe('');
46+
});
47+
48+
it('throws if file does not exist',async()=>{
49+
const{ fs}=memfs({'/dir/test.txt':'content'});
50+
const[,err]=awaitof(fs.openAsBlob('/dir/test-NOT-FOUND.txt'));
51+
expect(err).toBeInstanceOf(Error);
52+
expect((<any>err).code).toBe('ENOENT');
53+
});
54+
55+
it('throws EISDIR if path is a directory',async()=>{
56+
const{ fs}=memfs({'/dir/test.txt':'content'});
57+
const[,err]=awaitof(fs.openAsBlob('/dir'));
58+
expect(err).toBeInstanceOf(Error);
59+
expect((<any>err).code).toBe('EISDIR');
60+
});
61+
62+
it('works with Buffer paths',async()=>{
63+
const{ fs}=memfs({'/test.txt':'buffer path test'});
64+
constpathBuffer=Buffer.from('/test.txt');
65+
constblob=awaitfs.openAsBlob(pathBuffer);
66+
expect(blob).toBeInstanceOf(Blob);
67+
68+
consttext=awaitblob.text();
69+
expect(text).toBe('buffer path test');
70+
});
71+
72+
it('works with different path formats',async()=>{
73+
const{ fs}=memfs({'/path-test.txt':'path format test'});
74+
constblob=awaitfs.openAsBlob('/path-test.txt');
75+
expect(blob).toBeInstanceOf(Blob);
76+
77+
consttext=awaitblob.text();
78+
expect(text).toBe('path format test');
79+
});
80+
81+
it('handles large files',async()=>{
82+
constlargeContent='x'.repeat(10000);
83+
const{ fs}=memfs({'/large.txt':largeContent});
84+
constblob=awaitfs.openAsBlob('/large.txt');
85+
expect(blob).toBeInstanceOf(Blob);
86+
expect(blob.size).toBe(10000);
87+
88+
consttext=awaitblob.text();
89+
expect(text).toBe(largeContent);
90+
});
91+
92+
it('can read file through symlink',async()=>{
93+
const{ fs}=memfs({'/original.txt':'symlink test'});
94+
fs.symlinkSync('/original.txt','/link.txt');
95+
96+
constblob=awaitfs.openAsBlob('/link.txt');
97+
expect(blob).toBeInstanceOf(Blob);
98+
99+
consttext=awaitblob.text();
100+
expect(text).toBe('symlink test');
101+
});
102+
});

‎src/node/lists/fsCallbackApiList.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export const fsCallbackApiList: Array<keyof FsCallbackApi> = [
77
'chown',
88
'close',
99
'copyFile',
10+
'cp',
1011
'createReadStream',
1112
'createWriteStream',
1213
'exists',
@@ -24,6 +25,7 @@ export const fsCallbackApiList: Array<keyof FsCallbackApi> = [
2425
'mkdir',
2526
'mkdtemp',
2627
'open',
28+
'openAsBlob',
2729
'opendir',
2830
'read',
2931
'readv',
@@ -35,6 +37,7 @@ export const fsCallbackApiList: Array<keyof FsCallbackApi> = [
3537
'rm',
3638
'rmdir',
3739
'stat',
40+
'statfs',
3841
'symlink',
3942
'truncate',
4043
'unlink',

‎src/node/volume.ts‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,8 +1446,17 @@ export class Volume implements FsCallbackApi, FsSynchronousApi {
14461446
publicstatfsSync:FsSynchronousApi['statfsSync']=notImplemented;
14471447
/**@todo Implement statfs */
14481448
publicstatfs:FsCallbackApi['statfs']=notImplemented;
1449-
/**@todo Implement openAsBlob */
1450-
publicopenAsBlob:FsCallbackApi['openAsBlob']=notImplemented;
1449+
publicopenAsBlob=async(path:PathLike,options?:opts.IOpenAsBlobOptions):Promise<Blob>=>{
1450+
constfilename=pathToFilename(path);
1451+
constlink=this._core.getResolvedLinkOrThrow(filename,'open');
1452+
constnode=link.getNode();
1453+
if(node.isDirectory())throwcreateError(ERROR_CODE.EISDIR,'open',link.getPath());
1454+
1455+
constbuffer=node.getBuffer();
1456+
consttype=options?.type||'';
1457+
1458+
returnnewBlob([buffer],{ type});
1459+
};
14511460

14521461
/**@todo Implement glob */
14531462
publicglob:FsCallbackApi['glob']=notImplemented;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp