@zenfs/core 2.2.2 → 2.3.0
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/dist/backends/backend.js +6 -9
- package/dist/backends/cow.js +4 -4
- package/dist/backends/fetch.js +8 -6
- package/dist/backends/memory.js +4 -2
- package/dist/backends/passthrough.js +2 -0
- package/dist/backends/port.d.ts +16 -89
- package/dist/backends/port.js +35 -171
- package/dist/backends/single_buffer.d.ts +4 -2
- package/dist/backends/single_buffer.js +169 -195
- package/dist/backends/store/fs.js +50 -73
- package/dist/backends/store/map.js +1 -2
- package/dist/backends/store/store.js +23 -27
- package/dist/config.js +2 -3
- package/dist/context.js +2 -2
- package/dist/internal/credentials.d.ts +6 -0
- package/dist/internal/credentials.js +10 -0
- package/dist/internal/devices.js +7 -10
- package/dist/internal/file_index.js +3 -8
- package/dist/internal/filesystem.js +19 -12
- package/dist/internal/index_fs.js +3 -4
- package/dist/internal/inode.d.ts +2 -0
- package/dist/internal/inode.js +148 -185
- package/dist/internal/rpc.d.ts +143 -0
- package/dist/internal/rpc.js +251 -0
- package/dist/mixins/async.js +5 -6
- package/dist/mixins/mutexed.js +16 -10
- package/dist/path.js +3 -4
- package/dist/polyfills.js +51 -22
- package/dist/readline.js +32 -30
- package/dist/utils.d.ts +3 -2
- package/dist/utils.js +11 -5
- package/dist/vfs/acl.d.ts +2 -0
- package/dist/vfs/acl.js +48 -66
- package/dist/vfs/async.js +4 -4
- package/dist/vfs/dir.d.ts +4 -3
- package/dist/vfs/dir.js +16 -10
- package/dist/vfs/file.js +22 -18
- package/dist/vfs/ioctl.js +39 -62
- package/dist/vfs/promises.d.ts +33 -25
- package/dist/vfs/promises.js +56 -47
- package/dist/vfs/shared.js +7 -7
- package/dist/vfs/stats.js +104 -77
- package/dist/vfs/streams.js +11 -8
- package/dist/vfs/sync.d.ts +22 -11
- package/dist/vfs/sync.js +24 -27
- package/dist/vfs/types.d.ts +3 -8
- package/dist/vfs/watchers.js +9 -3
- package/dist/vfs/xattr.js +6 -12
- package/package.json +2 -2
- package/scripts/test.js +14 -7
- package/tests/backend/fetch.test.ts +14 -14
- package/tests/backend/port.test.ts +25 -17
- package/tests/common/context.test.ts +14 -0
- package/tests/common/handle.test.ts +5 -3
- package/tests/fetch/run.sh +2 -1
- package/tests/fs/scaling.test.ts +32 -0
- package/tests/fs/watch.test.ts +2 -5
- package/tests/setup/single-buffer.ts +1 -1
- package/tests/tsconfig.json +3 -2
- package/types/uint8array.d.ts +64 -0
package/dist/vfs/xattr.js
CHANGED
|
@@ -16,14 +16,13 @@ function checkName($, name, path, syscall) {
|
|
|
16
16
|
throw UV('ENOTSUP', syscall, path);
|
|
17
17
|
}
|
|
18
18
|
export async function get(path, name, opt = {}) {
|
|
19
|
-
var _a;
|
|
20
19
|
path = normalizePath(path);
|
|
21
20
|
const { fs, path: resolved } = resolveMount(path, this);
|
|
22
21
|
checkName(this, name, path, 'xattr.get');
|
|
23
22
|
const inode = await fs.stat(resolved).catch(rethrow('xattr.get', path));
|
|
24
23
|
if (checkAccess && !hasAccess(this, inode, R_OK))
|
|
25
24
|
throw UV('EACCES', 'xattr.get', path);
|
|
26
|
-
|
|
25
|
+
inode.attributes ??= new Attributes();
|
|
27
26
|
const value = inode.attributes.get(name);
|
|
28
27
|
if (!value)
|
|
29
28
|
throw UV('ENODATA', 'xattr.get', path);
|
|
@@ -31,7 +30,6 @@ export async function get(path, name, opt = {}) {
|
|
|
31
30
|
return opt.encoding == 'buffer' || !opt.encoding ? buffer : buffer.toString(opt.encoding);
|
|
32
31
|
}
|
|
33
32
|
export function getSync(path, name, opt = {}) {
|
|
34
|
-
var _a;
|
|
35
33
|
path = normalizePath(path);
|
|
36
34
|
checkName(this, name, path, 'xattr.get');
|
|
37
35
|
const { fs, path: resolved } = resolveMount(path, this);
|
|
@@ -44,7 +42,7 @@ export function getSync(path, name, opt = {}) {
|
|
|
44
42
|
}
|
|
45
43
|
if (checkAccess && !hasAccess(this, inode, R_OK))
|
|
46
44
|
throw UV('EACCES', 'xattr.get', path);
|
|
47
|
-
|
|
45
|
+
inode.attributes ??= new Attributes();
|
|
48
46
|
const value = inode.attributes.get(name);
|
|
49
47
|
if (!value)
|
|
50
48
|
throw UV('ENODATA', 'xattr.get', path);
|
|
@@ -60,14 +58,13 @@ export function getSync(path, name, opt = {}) {
|
|
|
60
58
|
* @param opt Options for the operation
|
|
61
59
|
*/
|
|
62
60
|
export async function set(path, name, value, opt = {}) {
|
|
63
|
-
var _a;
|
|
64
61
|
path = normalizePath(path);
|
|
65
62
|
const { fs, path: resolved } = resolveMount(path, this);
|
|
66
63
|
checkName(this, name, path, 'xattr.set');
|
|
67
64
|
const inode = await fs.stat(resolved).catch(rethrow('xattr.set', path));
|
|
68
65
|
if (checkAccess && !hasAccess(this, inode, W_OK))
|
|
69
66
|
throw UV('EACCES', 'xattr.set', path);
|
|
70
|
-
|
|
67
|
+
inode.attributes ??= new Attributes();
|
|
71
68
|
const attr = inode.attributes.get(name);
|
|
72
69
|
if (opt.create && attr)
|
|
73
70
|
throw UV('EEXIST', 'xattr.set', path);
|
|
@@ -85,7 +82,6 @@ export async function set(path, name, value, opt = {}) {
|
|
|
85
82
|
* @param opt Options for the operation
|
|
86
83
|
*/
|
|
87
84
|
export function setSync(path, name, value, opt = {}) {
|
|
88
|
-
var _a;
|
|
89
85
|
path = normalizePath(path);
|
|
90
86
|
const { fs, path: resolved } = resolveMount(path, this);
|
|
91
87
|
checkName(this, name, path, 'xattr.set');
|
|
@@ -98,7 +94,7 @@ export function setSync(path, name, value, opt = {}) {
|
|
|
98
94
|
}
|
|
99
95
|
if (checkAccess && !hasAccess(this, inode, W_OK))
|
|
100
96
|
throw UV('EACCES', 'xattr.set', path);
|
|
101
|
-
|
|
97
|
+
inode.attributes ??= new Attributes();
|
|
102
98
|
const attr = inode.attributes.get(name);
|
|
103
99
|
if (opt.create && attr)
|
|
104
100
|
throw UV('EEXIST', 'xattr.set', path);
|
|
@@ -119,14 +115,13 @@ export function setSync(path, name, value, opt = {}) {
|
|
|
119
115
|
* @param name Name of the attribute to remove
|
|
120
116
|
*/
|
|
121
117
|
export async function remove(path, name) {
|
|
122
|
-
var _a;
|
|
123
118
|
path = normalizePath(path);
|
|
124
119
|
const { fs, path: resolved } = resolveMount(path, this);
|
|
125
120
|
checkName(this, name, path, 'xattr.remove');
|
|
126
121
|
const inode = await fs.stat(resolved).catch(rethrow('xattr.remove', path));
|
|
127
122
|
if (checkAccess && !hasAccess(this, inode, W_OK))
|
|
128
123
|
throw UV('EACCES', 'xattr.remove', path);
|
|
129
|
-
|
|
124
|
+
inode.attributes ??= new Attributes();
|
|
130
125
|
const attr = inode.attributes.get(name);
|
|
131
126
|
if (!attr)
|
|
132
127
|
throw UV('ENODATA', 'xattr.remove', path);
|
|
@@ -140,7 +135,6 @@ export async function remove(path, name) {
|
|
|
140
135
|
* @param name Name of the attribute to remove
|
|
141
136
|
*/
|
|
142
137
|
export function removeSync(path, name) {
|
|
143
|
-
var _a;
|
|
144
138
|
path = normalizePath(path);
|
|
145
139
|
const { fs, path: resolved } = resolveMount(path, this);
|
|
146
140
|
checkName(this, name, path, 'xattr.remove');
|
|
@@ -153,7 +147,7 @@ export function removeSync(path, name) {
|
|
|
153
147
|
}
|
|
154
148
|
if (checkAccess && !hasAccess(this, inode, W_OK))
|
|
155
149
|
throw UV('EACCES', 'xattr.remove', path);
|
|
156
|
-
|
|
150
|
+
inode.attributes ??= new Attributes();
|
|
157
151
|
const attr = inode.attributes.get(name);
|
|
158
152
|
if (!attr)
|
|
159
153
|
throw UV('ENODATA', 'xattr.remove', path);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenfs/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "A filesystem, anywhere",
|
|
5
5
|
"funding": {
|
|
6
6
|
"type": "individual",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"buffer": "^6.0.3",
|
|
72
72
|
"eventemitter3": "^5.0.1",
|
|
73
73
|
"kerium": "^1.3.4",
|
|
74
|
-
"memium": "^0.2.
|
|
74
|
+
"memium": "^0.2.1",
|
|
75
75
|
"readable-stream": "^4.5.2",
|
|
76
76
|
"utilium": "^2.3.3"
|
|
77
77
|
},
|
package/scripts/test.js
CHANGED
|
@@ -89,11 +89,12 @@ if (options.ci) ci = await import('./ci.js');
|
|
|
89
89
|
options.verbose && options.force && console.debug('Forcing tests to exit (--test-force-exit)');
|
|
90
90
|
|
|
91
91
|
if (options.build) {
|
|
92
|
-
!options.quiet &&
|
|
92
|
+
!options.quiet && process.stdout.write('Building... ');
|
|
93
93
|
try {
|
|
94
94
|
execSync('npm run build');
|
|
95
|
+
console.log('done.');
|
|
95
96
|
} catch {
|
|
96
|
-
console.warn('
|
|
97
|
+
console.warn('failed, continuing without it.');
|
|
97
98
|
}
|
|
98
99
|
}
|
|
99
100
|
|
|
@@ -141,17 +142,19 @@ async function status(name) {
|
|
|
141
142
|
return color(`(${delta} ${unit})`, '2;37');
|
|
142
143
|
};
|
|
143
144
|
|
|
145
|
+
const maybeName = options.verbose ? `: ${name}` : '';
|
|
146
|
+
|
|
144
147
|
return {
|
|
145
148
|
async pass() {
|
|
146
|
-
if (!options.quiet) console.log(`${color('passed', 32)}
|
|
149
|
+
if (!options.quiet) console.log(`${color('passed', 32)}${maybeName} ${time()}`);
|
|
147
150
|
if (options.ci) await ci.completeCheck(name, 'success');
|
|
148
151
|
},
|
|
149
152
|
async skip() {
|
|
150
|
-
if (!options.quiet) console.log(`${color('skipped', 33)}
|
|
153
|
+
if (!options.quiet) console.log(`${color('skipped', 33)}${maybeName} ${time()}`);
|
|
151
154
|
if (options.ci) await ci.completeCheck(name, 'skipped');
|
|
152
155
|
},
|
|
153
156
|
async fail() {
|
|
154
|
-
console.error(`${color('failed', '1;31')}
|
|
157
|
+
console.error(`${color('failed', '1;31')}${maybeName} ${time()}`);
|
|
155
158
|
if (options.ci) await ci.completeCheck(name, 'failure');
|
|
156
159
|
process.exitCode = 1;
|
|
157
160
|
if (options['exit-on-fail']) process.exit();
|
|
@@ -163,7 +166,7 @@ if (!options.preserve) rmSync(options.coverage, { force: true, recursive: true }
|
|
|
163
166
|
mkdirSync(options.coverage, { recursive: true });
|
|
164
167
|
|
|
165
168
|
if (options.common) {
|
|
166
|
-
!options.quiet &&
|
|
169
|
+
!options.quiet && process.stdout.write('Running common tests...' + (options.verbose ? '\n' : ' '));
|
|
167
170
|
const { pass, fail } = await status('Common tests');
|
|
168
171
|
try {
|
|
169
172
|
execSync(
|
|
@@ -187,10 +190,14 @@ for (const setupFile of positionals) {
|
|
|
187
190
|
}
|
|
188
191
|
|
|
189
192
|
process.env.SETUP = setupFile;
|
|
193
|
+
process.env.VERBOSE = +options.verbose;
|
|
190
194
|
|
|
191
195
|
const name = options['file-names'] && !options.ci ? setupFile : parse(setupFile).name;
|
|
192
196
|
|
|
193
|
-
!options.quiet
|
|
197
|
+
if (!options.quiet) {
|
|
198
|
+
if (options.verbose) console.log('Running tests:', name);
|
|
199
|
+
else process.stdout.write(`Running tests: ${name}... `);
|
|
200
|
+
}
|
|
194
201
|
|
|
195
202
|
const { pass, fail, skip } = await status(name);
|
|
196
203
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
import { suite, test } from 'node:test';
|
|
3
|
+
import { after, suite, test } from 'node:test';
|
|
4
4
|
import { Worker } from 'node:worker_threads';
|
|
5
5
|
import { Fetch, configureSingle, fs, mounts, type FetchFS } from '../../dist/index.js';
|
|
6
6
|
import { baseUrl, defaultEntries, indexPath, whenServerReady } from '../fetch/config.js';
|
|
@@ -12,17 +12,15 @@ const server = new Worker(join(import.meta.dirname, '../fetch/server.js'));
|
|
|
12
12
|
|
|
13
13
|
await whenServerReady();
|
|
14
14
|
|
|
15
|
-
await
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
index: baseUrl + indexPath,
|
|
23
|
-
});
|
|
24
|
-
});
|
|
15
|
+
await configureSingle({
|
|
16
|
+
backend: Fetch,
|
|
17
|
+
disableAsyncCache: true,
|
|
18
|
+
remoteWrite: true,
|
|
19
|
+
baseUrl,
|
|
20
|
+
index: baseUrl + indexPath,
|
|
21
|
+
});
|
|
25
22
|
|
|
23
|
+
suite('Fetch with `disableAsyncCache`', () => {
|
|
26
24
|
test('Read and write file', async () => {
|
|
27
25
|
await fs.promises.writeFile('/example', 'test');
|
|
28
26
|
|
|
@@ -45,9 +43,11 @@ await suite('Fetch with `disableAsyncCache`', () => {
|
|
|
45
43
|
|
|
46
44
|
test('Uncached synchronous operations throw', async () => {
|
|
47
45
|
assert.throws(() => fs.readFileSync('/x.txt', 'utf8'), { code: 'EAGAIN' });
|
|
48
|
-
await (mounts.get('/') as FetchFS)._asyncDone;
|
|
49
46
|
});
|
|
50
47
|
});
|
|
51
48
|
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
after(async () => {
|
|
50
|
+
await (mounts.get('/') as FetchFS)._asyncDone;
|
|
51
|
+
await server.terminate();
|
|
52
|
+
server.unref();
|
|
53
|
+
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
|
-
import { suite, test } from 'node:test';
|
|
2
|
+
import { after, suite, test } from 'node:test';
|
|
3
3
|
import { MessageChannel, Worker } from 'node:worker_threads';
|
|
4
|
-
import { Port, attachFS
|
|
4
|
+
import { Port, attachFS } from '../../dist/backends/port.js';
|
|
5
5
|
import type { InMemoryStore, StoreFS } from '../../dist/index.js';
|
|
6
|
-
import { InMemory, configure, configureSingle, fs, resolveMountConfig } from '../../dist/index.js';
|
|
6
|
+
import { InMemory, configure, configureSingle, fs, resolveMountConfig, waitOnline } from '../../dist/index.js';
|
|
7
7
|
import { setupLogs } from '../logs.js';
|
|
8
8
|
setupLogs();
|
|
9
9
|
|
|
@@ -29,16 +29,18 @@ await suite('Timeout', { timeout: 1000 }, () => {
|
|
|
29
29
|
|
|
30
30
|
await assert.rejects(configured, { code: 'EIO', message: /RPC Failed/ });
|
|
31
31
|
});
|
|
32
|
-
});
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
after(() => {
|
|
34
|
+
timeoutChannel.port1.unref();
|
|
35
|
+
});
|
|
36
|
+
});
|
|
35
37
|
|
|
36
38
|
// Test configuration
|
|
37
39
|
|
|
38
40
|
const configPort = new Worker(import.meta.dirname + '/config.worker.js');
|
|
39
41
|
await waitOnline(configPort);
|
|
40
42
|
|
|
41
|
-
|
|
43
|
+
suite('Remote FS with resolveRemoteMount', () => {
|
|
42
44
|
const content = 'FS is in a port';
|
|
43
45
|
|
|
44
46
|
test('Configuration', async () => {
|
|
@@ -52,10 +54,12 @@ await suite('Remote FS with resolveRemoteMount', () => {
|
|
|
52
54
|
test('Read', async () => {
|
|
53
55
|
assert.equal(await fs.promises.readFile('/test', 'utf8'), content);
|
|
54
56
|
});
|
|
55
|
-
});
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
configPort.
|
|
58
|
+
after(async () => {
|
|
59
|
+
await configPort.terminate();
|
|
60
|
+
configPort.unref();
|
|
61
|
+
});
|
|
62
|
+
});
|
|
59
63
|
|
|
60
64
|
// Test using a message channel
|
|
61
65
|
|
|
@@ -87,12 +91,14 @@ await suite('FS with MessageChannel', () => {
|
|
|
87
91
|
test('readFileSync should throw', () => {
|
|
88
92
|
assert.throws(() => fs.readFileSync('/test', 'utf8'), { code: 'ENOTSUP' });
|
|
89
93
|
});
|
|
90
|
-
});
|
|
91
94
|
|
|
92
|
-
|
|
93
|
-
channel.
|
|
94
|
-
channel.
|
|
95
|
-
channel.
|
|
95
|
+
after(() => {
|
|
96
|
+
channel.port1.close();
|
|
97
|
+
channel.port2.close();
|
|
98
|
+
channel.port1.unref();
|
|
99
|
+
channel.port2.unref();
|
|
100
|
+
});
|
|
101
|
+
});
|
|
96
102
|
|
|
97
103
|
// Test using a worker
|
|
98
104
|
|
|
@@ -112,7 +118,9 @@ await suite('Remote FS', () => {
|
|
|
112
118
|
test('Read', async () => {
|
|
113
119
|
assert.equal(await fs.promises.readFile('/test', 'utf8'), content);
|
|
114
120
|
});
|
|
115
|
-
});
|
|
116
121
|
|
|
117
|
-
|
|
118
|
-
remotePort.
|
|
122
|
+
after(async () => {
|
|
123
|
+
await remotePort.terminate();
|
|
124
|
+
remotePort.unref();
|
|
125
|
+
});
|
|
126
|
+
});
|
|
@@ -3,6 +3,7 @@ import { suite, test } from 'node:test';
|
|
|
3
3
|
import { canary } from 'utilium';
|
|
4
4
|
import { bindContext } from '../../dist/context.js';
|
|
5
5
|
import * as fs from '../../dist/vfs/index.js';
|
|
6
|
+
import { configure, InMemory } from '../../dist/index.js';
|
|
6
7
|
|
|
7
8
|
fs.mkdirSync('/ctx');
|
|
8
9
|
const { fs: ctx } = bindContext({ root: '/ctx' });
|
|
@@ -58,4 +59,17 @@ suite('Context', () => {
|
|
|
58
59
|
await watcher.return!();
|
|
59
60
|
await promise;
|
|
60
61
|
});
|
|
62
|
+
|
|
63
|
+
test('Path resolution of / with context root and mount point being the same', async () => {
|
|
64
|
+
// @zenfs/core#226
|
|
65
|
+
await configure({
|
|
66
|
+
mounts: { '/bananas': InMemory },
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const bananas = bindContext({ root: '/bananas' });
|
|
70
|
+
|
|
71
|
+
fs.writeFileSync('/bananas/yellow', 'true');
|
|
72
|
+
|
|
73
|
+
assert.deepEqual(bananas.fs.readdirSync('/'), ['yellow']);
|
|
74
|
+
});
|
|
61
75
|
});
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
|
-
import { suite, test } from 'node:test';
|
|
2
|
+
import { after, suite, test } from 'node:test';
|
|
3
3
|
import { wait } from 'utilium';
|
|
4
4
|
import { constants, type FileHandle, open } from '../../dist/vfs/promises.js';
|
|
5
5
|
|
|
6
6
|
const content = 'The cake is a lie',
|
|
7
7
|
appended = '\nAnother lie';
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
const handle: FileHandle = await open('./test.txt', 'ws+');
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
suite('FileHandle', () => {
|
|
12
12
|
test('writeFile', async () => {
|
|
13
13
|
await handle.writeFile(content);
|
|
14
14
|
await handle.sync();
|
|
@@ -63,3 +63,5 @@ await suite('FileHandle', () => {
|
|
|
63
63
|
assert.deepEqual(lines, ['first line', 'second line', 'third line']);
|
|
64
64
|
});
|
|
65
65
|
});
|
|
66
|
+
|
|
67
|
+
after(() => handle.close());
|
package/tests/fetch/run.sh
CHANGED
|
@@ -6,7 +6,8 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
|
|
6
6
|
node $SCRIPT_DIR/server.js &
|
|
7
7
|
PID=$!
|
|
8
8
|
|
|
9
|
-
echo "Waiting for server to start..."
|
|
9
|
+
echo -n "Waiting for server to start..."
|
|
10
|
+
if [ -n "$VERBOSE" ]; then echo; fi
|
|
10
11
|
until nc -z localhost 26514; do
|
|
11
12
|
sleep 0.25
|
|
12
13
|
done
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { suite, test } from 'node:test';
|
|
3
|
+
import { fs } from '../common.js';
|
|
4
|
+
|
|
5
|
+
const n_files = 130;
|
|
6
|
+
const huge_size = 0x1000000;
|
|
7
|
+
|
|
8
|
+
// Tests for having a lot of various things (number of inodes/files, individual file size, etc.).
|
|
9
|
+
suite('Scaling', () => {
|
|
10
|
+
test('Lots of inodes/files', async () => {
|
|
11
|
+
fs.mkdirSync('/n');
|
|
12
|
+
|
|
13
|
+
for (let i = 0; i < n_files; i++) {
|
|
14
|
+
fs.writeFileSync('/n/' + i, i.toString(16));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
assert.equal(fs.readdirSync('/n').length, n_files);
|
|
18
|
+
|
|
19
|
+
const results = [];
|
|
20
|
+
|
|
21
|
+
for (let i = 0; i < n_files; i++) {
|
|
22
|
+
results.push(fs.promises.readFile('/n/' + i, 'utf8').then(val => assert.equal(val, i.toString(16))));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
await Promise.all(results);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('Singular file size', () => {
|
|
29
|
+
fs.writeFileSync('/huge', new Uint8Array(huge_size));
|
|
30
|
+
assert.equal(fs.statSync('/huge').size, huge_size);
|
|
31
|
+
});
|
|
32
|
+
});
|
package/tests/fs/watch.test.ts
CHANGED
|
@@ -9,9 +9,9 @@ await fs.promises.mkdir(testDir);
|
|
|
9
9
|
await fs.promises.writeFile(testFile, 'Initial content');
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* @todo convert using watcher to void discards pending ES proposal
|
|
12
|
+
* @todo convert `using watcher = ...` to void discards pending ES proposal
|
|
13
13
|
*/
|
|
14
|
-
|
|
14
|
+
suite('Watch', async () => {
|
|
15
15
|
test('Events emitted on file change', async () => {
|
|
16
16
|
const { promise, resolve } = Promise.withResolvers<[string, string]>();
|
|
17
17
|
|
|
@@ -155,6 +155,3 @@ await suite('Watch', () => {
|
|
|
155
155
|
await promise;
|
|
156
156
|
});
|
|
157
157
|
});
|
|
158
|
-
|
|
159
|
-
await fs.promises.rm(testFile);
|
|
160
|
-
await fs.promises.rm(testDir, { recursive: true, force: true });
|
package/tests/tsconfig.json
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
"noEmit": true,
|
|
7
7
|
"esModuleInterop": true,
|
|
8
8
|
"allowSyntheticDefaultImports": true,
|
|
9
|
-
"allowJs": true
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
"rootDir": ".."
|
|
10
11
|
},
|
|
11
|
-
"include": ["**/*.ts", "*.ts", "**/*.js"]
|
|
12
|
+
"include": ["**/*.ts", "*.ts", "**/*.js", "../types/uint8array.d.ts"]
|
|
12
13
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
See:
|
|
3
|
+
https://developer.mozilla.org/Web/JavaScript/Reference/Global_Objects/Uint8Array/toBase64
|
|
4
|
+
https://github.com/microsoft/TypeScript/pull/61696
|
|
5
|
+
https://github.com/microsoft/TypeScript/issues/61695
|
|
6
|
+
|
|
7
|
+
@todo Remove when TypeScript 5.9 is released
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
interface Uint8ArrayConstructor {
|
|
11
|
+
/**
|
|
12
|
+
* Creates a new `Uint8Array` from a base64-encoded string.
|
|
13
|
+
* @param string The base64-encoded string.
|
|
14
|
+
* @param options If provided, specifies the alphabet and handling of the last chunk.
|
|
15
|
+
* @returns A new `Uint8Array` instance.
|
|
16
|
+
* @throws {SyntaxError} If the input string contains characters outside the specified alphabet, or if the last
|
|
17
|
+
* chunk is inconsistent with the `lastChunkHandling` option.
|
|
18
|
+
*/
|
|
19
|
+
fromBase64: (string: string) => Uint8Array;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Creates a new `Uint8Array` from a base16-encoded string.
|
|
23
|
+
* @returns A new `Uint8Array` instance.
|
|
24
|
+
*/
|
|
25
|
+
fromHex: (string: string) => Uint8Array;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface Uint8Array<TArrayBuffer extends ArrayBufferLike> {
|
|
29
|
+
/**
|
|
30
|
+
* Converts the `Uint8Array` to a base64-encoded string.
|
|
31
|
+
* @param options If provided, sets the alphabet and padding behavior used.
|
|
32
|
+
* @returns A base64-encoded string.
|
|
33
|
+
*/
|
|
34
|
+
toBase64: () => string;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Sets the `Uint8Array` from a base64-encoded string.
|
|
38
|
+
* @param string The base64-encoded string.
|
|
39
|
+
* @param options If provided, specifies the alphabet and handling of the last chunk.
|
|
40
|
+
* @returns An object containing the number of bytes read and written.
|
|
41
|
+
* @throws {SyntaxError} If the input string contains characters outside the specified alphabet, or if the last
|
|
42
|
+
* chunk is inconsistent with the `lastChunkHandling` option.
|
|
43
|
+
*/
|
|
44
|
+
setFromBase64?: (string: string) => {
|
|
45
|
+
read: number;
|
|
46
|
+
written: number;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Converts the `Uint8Array` to a base16-encoded string.
|
|
51
|
+
* @returns A base16-encoded string.
|
|
52
|
+
*/
|
|
53
|
+
toHex: () => string;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Sets the `Uint8Array` from a base16-encoded string.
|
|
57
|
+
* @param string The base16-encoded string.
|
|
58
|
+
* @returns An object containing the number of bytes read and written.
|
|
59
|
+
*/
|
|
60
|
+
setFromHex?: (string: string) => {
|
|
61
|
+
read: number;
|
|
62
|
+
written: number;
|
|
63
|
+
};
|
|
64
|
+
}
|