@zenfs/core 2.4.1 → 2.4.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.
Files changed (101) hide show
  1. package/COPYING.md +24 -0
  2. package/{readme.md → README.md} +16 -74
  3. package/dist/backends/backend.d.ts +1 -1
  4. package/dist/backends/fetch.js +1 -1
  5. package/dist/backends/memory.js +1 -1
  6. package/dist/backends/passthrough.d.ts +1 -2
  7. package/dist/backends/single_buffer.d.ts +1 -1
  8. package/dist/backends/single_buffer.js +27 -24
  9. package/dist/backends/store/fs.js +4 -4
  10. package/dist/config.js +15 -15
  11. package/dist/context.js +3 -2
  12. package/dist/index.d.ts +9 -3
  13. package/dist/index.js +9 -4
  14. package/dist/internal/contexts.d.ts +5 -4
  15. package/dist/internal/devices.js +1 -1
  16. package/dist/internal/error.d.ts +11 -2
  17. package/dist/internal/error.js +38 -2
  18. package/dist/internal/file_index.js +1 -1
  19. package/dist/internal/index.d.ts +1 -0
  20. package/dist/internal/index.js +2 -1
  21. package/dist/internal/index_fs.js +1 -1
  22. package/dist/internal/inode.d.ts +51 -2
  23. package/dist/internal/inode.js +18 -2
  24. package/dist/mixins/shared.js +1 -1
  25. package/dist/node/async.d.ts +278 -0
  26. package/dist/node/async.js +518 -0
  27. package/dist/node/compat.d.ts +4 -0
  28. package/dist/node/compat.js +6 -0
  29. package/dist/node/dir.d.ts +78 -0
  30. package/dist/node/dir.js +150 -0
  31. package/dist/node/index.d.ts +8 -0
  32. package/dist/node/index.js +8 -0
  33. package/dist/{vfs → node}/promises.d.ts +10 -66
  34. package/dist/{vfs → node}/promises.js +141 -478
  35. package/dist/{vfs → node}/stats.d.ts +0 -4
  36. package/dist/{vfs → node}/stats.js +1 -16
  37. package/dist/{vfs → node}/streams.js +2 -2
  38. package/dist/node/sync.d.ts +252 -0
  39. package/dist/node/sync.js +682 -0
  40. package/dist/node/types.d.ts +21 -0
  41. package/dist/utils.d.ts +1 -7
  42. package/dist/utils.js +0 -6
  43. package/dist/vfs/acl.js +1 -1
  44. package/dist/vfs/async.d.ts +22 -278
  45. package/dist/vfs/async.js +212 -501
  46. package/dist/vfs/dir.d.ts +5 -82
  47. package/dist/vfs/dir.js +5 -233
  48. package/dist/vfs/file.d.ts +52 -13
  49. package/dist/vfs/file.js +167 -25
  50. package/dist/vfs/flags.js +1 -1
  51. package/dist/vfs/index.d.ts +2 -5
  52. package/dist/vfs/index.js +2 -5
  53. package/dist/vfs/shared.d.ts +25 -1
  54. package/dist/vfs/shared.js +6 -4
  55. package/dist/vfs/sync.d.ts +17 -245
  56. package/dist/vfs/sync.js +129 -773
  57. package/dist/vfs/watchers.d.ts +1 -1
  58. package/dist/vfs/watchers.js +2 -2
  59. package/dist/vfs/xattr.js +1 -1
  60. package/eslint.shared.js +1 -0
  61. package/package.json +7 -5
  62. package/scripts/make-index.js +5 -29
  63. package/scripts/test.js +59 -51
  64. package/tests/backend/fetch.test.ts +2 -2
  65. package/tests/backend/port.test.ts +2 -3
  66. package/tests/backend/single-buffer.test.ts +48 -1
  67. package/tests/common/casefold.test.ts +1 -1
  68. package/tests/common/context.test.ts +11 -4
  69. package/tests/common/devices.test.ts +3 -3
  70. package/tests/common/handle.test.ts +4 -3
  71. package/tests/common/inode.test.ts +2 -2
  72. package/tests/common/mounts.test.ts +1 -3
  73. package/tests/common/mutex.test.ts +1 -3
  74. package/tests/common/path.test.ts +2 -2
  75. package/tests/common/readline.test.ts +1 -1
  76. package/tests/common.ts +5 -4
  77. package/tests/fetch/fetch.ts +1 -1
  78. package/tests/fs/dir.test.ts +3 -43
  79. package/tests/fs/directory.test.ts +4 -4
  80. package/tests/fs/errors.test.ts +2 -2
  81. package/tests/fs/links.test.ts +1 -1
  82. package/tests/fs/permissions.test.ts +3 -3
  83. package/tests/fs/read.test.ts +1 -1
  84. package/tests/fs/scaling.test.ts +1 -1
  85. package/tests/fs/stat.test.ts +1 -2
  86. package/tests/fs/times.test.ts +1 -1
  87. package/tests/fs/watch.test.ts +3 -2
  88. package/tests/setup/context.ts +1 -2
  89. package/tests/setup/cow.ts +1 -1
  90. package/tests/setup/index.ts +2 -2
  91. package/tests/setup/port.ts +1 -1
  92. package/tests/setup/single-buffer.ts +1 -1
  93. package/tests/setup.ts +4 -3
  94. package/dist/vfs/types.d.ts +0 -24
  95. package/tests/assignment.ts +0 -21
  96. /package/dist/{vfs/constants.d.ts → constants.d.ts} +0 -0
  97. /package/dist/{vfs/constants.js → constants.js} +0 -0
  98. /package/dist/{readline.d.ts → node/readline.d.ts} +0 -0
  99. /package/dist/{readline.js → node/readline.js} +0 -0
  100. /package/dist/{vfs → node}/streams.d.ts +0 -0
  101. /package/dist/{vfs → node}/types.js +0 -0
@@ -0,0 +1,682 @@
1
+ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
+ if (value !== null && value !== void 0) {
3
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
+ var dispose, inner;
5
+ if (async) {
6
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
+ dispose = value[Symbol.asyncDispose];
8
+ }
9
+ if (dispose === void 0) {
10
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
+ dispose = value[Symbol.dispose];
12
+ if (async) inner = dispose;
13
+ }
14
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
+ env.stack.push({ value: value, dispose: dispose, async: async });
17
+ }
18
+ else if (async) {
19
+ env.stack.push({ async: true });
20
+ }
21
+ return value;
22
+ };
23
+ var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
+ return function (env) {
25
+ function fail(e) {
26
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
+ env.hasError = true;
28
+ }
29
+ var r, s = 0;
30
+ function next() {
31
+ while (r = env.stack.pop()) {
32
+ try {
33
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
+ if (r.dispose) {
35
+ var result = r.dispose.call(r.value);
36
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
+ }
38
+ else s |= 1;
39
+ }
40
+ catch (e) {
41
+ fail(e);
42
+ }
43
+ }
44
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
+ if (env.hasError) throw env.error;
46
+ }
47
+ return next();
48
+ };
49
+ })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
+ var e = new Error(message);
51
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
+ });
53
+ import { Buffer } from 'buffer';
54
+ import { Errno, Exception, setUVMessage, UV } from 'kerium';
55
+ import { encodeUTF8 } from 'utilium';
56
+ import * as constants from '../constants.js';
57
+ import { wrap } from '../internal/error.js';
58
+ import { hasAccess, isDirectory } from '../internal/inode.js';
59
+ import { join, matchesGlob, parse } from '../path.js';
60
+ import { _tempDirName, globToRegex, normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '../utils.js';
61
+ import { checkAccess } from '../vfs/config.js';
62
+ import { deleteFD, fromFD, toFD } from '../vfs/file.js';
63
+ import * as flags from '../vfs/flags.js';
64
+ import { _statfs, resolveMount } from '../vfs/shared.js';
65
+ import * as _sync from '../vfs/sync.js';
66
+ import { emitChange } from '../vfs/watchers.js';
67
+ import { Dir, Dirent } from './dir.js';
68
+ import { BigIntStats, Stats } from './stats.js';
69
+ export function renameSync(oldPath, newPath) {
70
+ return _sync.rename.call(this, oldPath, newPath);
71
+ }
72
+ renameSync;
73
+ /**
74
+ * Test whether or not `path` exists by checking with the file system.
75
+ */
76
+ export function existsSync(path) {
77
+ path = normalizePath(path);
78
+ try {
79
+ const { fs, path: resolvedPath } = _sync.resolve(this, path);
80
+ return fs.existsSync(resolvedPath);
81
+ }
82
+ catch (e) {
83
+ if (e.errno == Errno.ENOENT)
84
+ return false;
85
+ throw e;
86
+ }
87
+ }
88
+ existsSync;
89
+ export function statSync(path, options) {
90
+ path = normalizePath(path);
91
+ const { fs, path: resolved } = _sync.resolve(this, path);
92
+ let stats;
93
+ try {
94
+ stats = fs.statSync(resolved);
95
+ }
96
+ catch (e) {
97
+ throw setUVMessage(Object.assign(e, { path }));
98
+ }
99
+ if (checkAccess && !hasAccess(this, stats, constants.R_OK))
100
+ throw UV('EACCES', { syscall: 'stat', path });
101
+ return options?.bigint ? new BigIntStats(stats) : new Stats(stats);
102
+ }
103
+ statSync;
104
+ export function lstatSync(path, options) {
105
+ path = normalizePath(path);
106
+ const { base, dir } = parse(path);
107
+ const { fs, path: parent } = _sync.resolve(this, dir);
108
+ const stats = wrap(fs, 'statSync', path)(base ? join(parent, base) : parent);
109
+ if (checkAccess && !hasAccess(this, stats, constants.R_OK))
110
+ throw UV('EACCES', { syscall: 'lstat', path });
111
+ return options?.bigint ? new BigIntStats(stats) : new Stats(stats);
112
+ }
113
+ lstatSync;
114
+ export function truncateSync(path, len = 0) {
115
+ const env_1 = { stack: [], error: void 0, hasError: false };
116
+ try {
117
+ const file = __addDisposableResource(env_1, _sync.open.call(this, path, { flag: 'r+' }), false);
118
+ len ||= 0;
119
+ if (len < 0)
120
+ throw UV('EINVAL', 'truncate', path.toString());
121
+ file.truncateSync(len);
122
+ }
123
+ catch (e_1) {
124
+ env_1.error = e_1;
125
+ env_1.hasError = true;
126
+ }
127
+ finally {
128
+ __disposeResources(env_1);
129
+ }
130
+ }
131
+ truncateSync;
132
+ export function unlinkSync(path) {
133
+ path = normalizePath(path);
134
+ const { fs, path: resolved } = resolveMount(path, this);
135
+ try {
136
+ if (checkAccess && !hasAccess(this, fs.statSync(resolved), constants.W_OK)) {
137
+ throw UV('EACCES', 'unlink');
138
+ }
139
+ fs.unlinkSync(resolved);
140
+ }
141
+ catch (e) {
142
+ throw setUVMessage(Object.assign(e, { path }));
143
+ }
144
+ emitChange(this, 'rename', path.toString());
145
+ }
146
+ unlinkSync;
147
+ /**
148
+ * Synchronous file open.
149
+ * @see https://nodejs.org/api/fs.html#fsopensyncpath-flags-mode
150
+ * @param flag {@link https://nodejs.org/api/fs.html#file-system-flags}
151
+ */
152
+ export function openSync(path, flag, mode = constants.F_OK) {
153
+ return toFD(_sync.open.call(this, path, { flag, mode }));
154
+ }
155
+ openSync;
156
+ /**
157
+ * Opens a file or symlink
158
+ * @internal
159
+ */
160
+ export function lopenSync(path, flag, mode) {
161
+ return toFD(_sync.open.call(this, path, { flag, mode, preserveSymlinks: true }));
162
+ }
163
+ export function readFileSync(path, _options = {}) {
164
+ const env_2 = { stack: [], error: void 0, hasError: false };
165
+ try {
166
+ const options = normalizeOptions(_options, null, 'r', 0o644);
167
+ const flag = flags.parse(options.flag);
168
+ if (flag & constants.O_WRONLY)
169
+ throw UV('EBADF', 'read', path.toString());
170
+ const file = __addDisposableResource(env_2, typeof path == 'number'
171
+ ? fromFD(this, path)
172
+ : _sync.open.call(this, path.toString(), { flag: options.flag, mode: 0o644, preserveSymlinks: false }), false);
173
+ const { size } = file.stat();
174
+ const data = Buffer.alloc(size);
175
+ file.readSync(data, 0, size, 0);
176
+ return options.encoding ? data.toString(options.encoding) : data;
177
+ }
178
+ catch (e_2) {
179
+ env_2.error = e_2;
180
+ env_2.hasError = true;
181
+ }
182
+ finally {
183
+ __disposeResources(env_2);
184
+ }
185
+ }
186
+ readFileSync;
187
+ export function writeFileSync(path, data, _options = {}) {
188
+ const env_3 = { stack: [], error: void 0, hasError: false };
189
+ try {
190
+ const options = normalizeOptions(_options, 'utf8', 'w+', 0o644);
191
+ const flag = flags.parse(options.flag);
192
+ if (!(flag & constants.O_WRONLY || flag & constants.O_RDWR)) {
193
+ throw new Exception(Errno.EINVAL, 'Flag passed to writeFile must allow for writing');
194
+ }
195
+ if (typeof data != 'string' && !options.encoding) {
196
+ throw new Exception(Errno.EINVAL, 'Encoding not specified');
197
+ }
198
+ const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
199
+ if (!encodedData) {
200
+ throw new Exception(Errno.EINVAL, 'Data not specified');
201
+ }
202
+ const file = __addDisposableResource(env_3, typeof path == 'number'
203
+ ? fromFD(this, path)
204
+ : _sync.open.call(this, path.toString(), {
205
+ flag,
206
+ mode: options.mode,
207
+ preserveSymlinks: true,
208
+ }), false);
209
+ file.writeSync(encodedData, 0, encodedData.byteLength, 0);
210
+ emitChange(this, 'change', path.toString());
211
+ }
212
+ catch (e_3) {
213
+ env_3.error = e_3;
214
+ env_3.hasError = true;
215
+ }
216
+ finally {
217
+ __disposeResources(env_3);
218
+ }
219
+ }
220
+ writeFileSync;
221
+ /**
222
+ * Asynchronously append data to a file, creating the file if it not yet exists.
223
+ * @option encoding Defaults to `'utf8'`.
224
+ * @option mode Defaults to `0644`.
225
+ * @option flag Defaults to `'a+'`.
226
+ */
227
+ export function appendFileSync(filename, data, _options = {}) {
228
+ const options = normalizeOptions(_options, 'utf8', 'a+', 0o644);
229
+ const flag = flags.parse(options.flag);
230
+ if (!(flag & constants.O_APPEND)) {
231
+ throw new Exception(Errno.EINVAL, 'Flag passed to appendFile must allow for appending');
232
+ }
233
+ if (typeof data != 'string' && !options.encoding) {
234
+ throw new Exception(Errno.EINVAL, 'Encoding not specified');
235
+ }
236
+ const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
237
+ const file = typeof filename == 'number'
238
+ ? fromFD(this, filename)
239
+ : _sync.open.call(this, normalizePath(filename), {
240
+ flag,
241
+ mode: options.mode,
242
+ preserveSymlinks: true,
243
+ });
244
+ file.writeSync(encodedData, 0, encodedData.byteLength);
245
+ if (typeof file != 'number')
246
+ file.closeSync();
247
+ }
248
+ appendFileSync;
249
+ export function fstatSync(fd, options) {
250
+ const stats = fromFD(this, fd).stat();
251
+ return options?.bigint ? new BigIntStats(stats) : new Stats(stats);
252
+ }
253
+ fstatSync;
254
+ export function closeSync(fd) {
255
+ fromFD(this, fd).closeSync();
256
+ deleteFD(this, fd);
257
+ }
258
+ closeSync;
259
+ export function ftruncateSync(fd, len = 0) {
260
+ len ||= 0;
261
+ if (len < 0) {
262
+ throw new Exception(Errno.EINVAL);
263
+ }
264
+ fromFD(this, fd).truncateSync(len);
265
+ }
266
+ ftruncateSync;
267
+ export function fsyncSync(fd) {
268
+ fromFD(this, fd).syncSync();
269
+ }
270
+ fsyncSync;
271
+ export function fdatasyncSync(fd) {
272
+ fromFD(this, fd).datasyncSync();
273
+ }
274
+ fdatasyncSync;
275
+ export function writeSync(fd, data, posOrOff, lenOrEnc, pos) {
276
+ let buffer, offset, length, position;
277
+ if (typeof data === 'string') {
278
+ // Signature 1: (fd, string, [position?, [encoding?]])
279
+ position = typeof posOrOff === 'number' ? posOrOff : null;
280
+ const encoding = typeof lenOrEnc === 'string' ? lenOrEnc : 'utf8';
281
+ offset = 0;
282
+ buffer = Buffer.from(data, encoding);
283
+ length = buffer.byteLength;
284
+ }
285
+ else {
286
+ // Signature 2: (fd, buffer, offset, length, position?)
287
+ buffer = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
288
+ offset = posOrOff;
289
+ length = lenOrEnc;
290
+ position = typeof pos === 'number' ? pos : null;
291
+ }
292
+ const file = fromFD(this, fd);
293
+ position ??= file.position;
294
+ const bytesWritten = file.writeSync(buffer, offset, length, position);
295
+ emitChange(this, 'change', file.path);
296
+ return bytesWritten;
297
+ }
298
+ writeSync;
299
+ /**
300
+ * Read data from the file specified by `fd`.
301
+ * @param buffer The buffer that the data will be written to.
302
+ * @param offset The offset within the buffer where writing will start.
303
+ * @param length An integer specifying the number of bytes to read.
304
+ * @param position An integer specifying where to begin reading from in the file.
305
+ * If position is null, data will be read from the current file position.
306
+ */
307
+ export function readSync(fd, buffer, options, length, position) {
308
+ const file = fromFD(this, fd);
309
+ const offset = typeof options == 'object' ? options.offset : options;
310
+ if (typeof options == 'object') {
311
+ length = options.length;
312
+ position = options.position;
313
+ }
314
+ if (position && position > Number.MAX_SAFE_INTEGER)
315
+ throw UV('EINVAL');
316
+ if (typeof position == 'bigint')
317
+ position = Number(position);
318
+ position = Number.isSafeInteger(position) ? position : file.position;
319
+ return file.readSync(buffer, offset, length, position);
320
+ }
321
+ readSync;
322
+ export function fchownSync(fd, uid, gid) {
323
+ fromFD(this, fd).chownSync(uid, gid);
324
+ }
325
+ fchownSync;
326
+ export function fchmodSync(fd, mode) {
327
+ const numMode = normalizeMode(mode, -1);
328
+ if (numMode < 0) {
329
+ throw new Exception(Errno.EINVAL, `Invalid mode.`);
330
+ }
331
+ fromFD(this, fd).chmodSync(numMode);
332
+ }
333
+ fchmodSync;
334
+ /**
335
+ * Change the file timestamps of a file referenced by the supplied file descriptor.
336
+ */
337
+ export function futimesSync(fd, atime, mtime) {
338
+ fromFD(this, fd).utimesSync(normalizeTime(atime), normalizeTime(mtime));
339
+ }
340
+ futimesSync;
341
+ export function rmdirSync(path) {
342
+ path = normalizePath(path);
343
+ const { fs, path: resolved } = _sync.resolve(this, path);
344
+ const stats = wrap(fs, 'statSync', path)(resolved);
345
+ if (!isDirectory(stats))
346
+ throw UV('ENOTDIR', 'rmdir', path);
347
+ if (checkAccess && !hasAccess(this, stats, constants.W_OK))
348
+ throw UV('EACCES', 'rmdir', path);
349
+ wrap(fs, 'rmdirSync', path)(resolved);
350
+ emitChange(this, 'rename', path.toString());
351
+ }
352
+ rmdirSync;
353
+ export function mkdirSync(path, options) {
354
+ options = typeof options === 'object' ? options : { mode: options };
355
+ const mode = normalizeMode(options?.mode, 0o777);
356
+ return _sync.mkdir.call(this, path, { ...options, mode });
357
+ }
358
+ mkdirSync;
359
+ export function readdirSync(path, options) {
360
+ options = typeof options === 'object' ? options : { encoding: options };
361
+ path = normalizePath(path);
362
+ const entries = [];
363
+ const rawEntries = _sync.readdir.call(this, path, options ?? undefined);
364
+ for (const raw of rawEntries) {
365
+ if (options?.withFileTypes) {
366
+ entries.push(Dirent.from(raw, options.encoding));
367
+ }
368
+ else if (options?.encoding == 'buffer') {
369
+ entries.push(Buffer.from(raw.path));
370
+ }
371
+ else {
372
+ entries.push(raw.path);
373
+ }
374
+ }
375
+ return entries;
376
+ }
377
+ readdirSync;
378
+ export function linkSync(targetPath, linkPath) {
379
+ return _sync.link.call(this, targetPath, linkPath);
380
+ }
381
+ linkSync;
382
+ /**
383
+ * Synchronous `symlink`.
384
+ * @param target target path
385
+ * @param path link path
386
+ * @param type can be either `'dir'` or `'file'` (default is `'file'`)
387
+ */
388
+ export function symlinkSync(target, path, type = 'file') {
389
+ const env_4 = { stack: [], error: void 0, hasError: false };
390
+ try {
391
+ if (!['file', 'dir', 'junction'].includes(type))
392
+ throw new TypeError('Invalid symlink type: ' + type);
393
+ path = normalizePath(path);
394
+ const file = __addDisposableResource(env_4, _sync.open.call(this, path, { flag: 'wx', mode: 0o644 }), false);
395
+ file.writeSync(encodeUTF8(normalizePath(target, true)));
396
+ file.chmodSync(constants.S_IFLNK);
397
+ }
398
+ catch (e_4) {
399
+ env_4.error = e_4;
400
+ env_4.hasError = true;
401
+ }
402
+ finally {
403
+ __disposeResources(env_4);
404
+ }
405
+ }
406
+ symlinkSync;
407
+ export function readlinkSync(path, options) {
408
+ const buf = Buffer.from(_sync.readlink.call(this, path));
409
+ const encoding = typeof options == 'object' ? options?.encoding : options;
410
+ if (encoding == 'buffer') {
411
+ return buf;
412
+ }
413
+ // always defaults to utf-8 to avoid wrangler (cloudflare) worker "unknown encoding" exception
414
+ return buf.toString(encoding ?? 'utf-8');
415
+ }
416
+ readlinkSync;
417
+ export function chownSync(path, uid, gid) {
418
+ const env_5 = { stack: [], error: void 0, hasError: false };
419
+ try {
420
+ const handle = __addDisposableResource(env_5, _sync.open.call(this, path, { flag: 'r+', mode: constants.F_OK }), false);
421
+ handle.chownSync(uid, gid);
422
+ }
423
+ catch (e_5) {
424
+ env_5.error = e_5;
425
+ env_5.hasError = true;
426
+ }
427
+ finally {
428
+ __disposeResources(env_5);
429
+ }
430
+ }
431
+ chownSync;
432
+ export function lchownSync(path, uid, gid) {
433
+ const fd = lopenSync.call(this, path, 'r+');
434
+ fchownSync.call(this, fd, uid, gid);
435
+ closeSync.call(this, fd);
436
+ }
437
+ lchownSync;
438
+ export function chmodSync(path, mode) {
439
+ const fd = openSync.call(this, path, 'r+');
440
+ fchmodSync.call(this, fd, mode);
441
+ closeSync.call(this, fd);
442
+ }
443
+ chmodSync;
444
+ export function lchmodSync(path, mode) {
445
+ const fd = lopenSync.call(this, path, 'r+');
446
+ fchmodSync.call(this, fd, mode);
447
+ closeSync.call(this, fd);
448
+ }
449
+ lchmodSync;
450
+ /**
451
+ * Change file timestamps of the file referenced by the supplied path.
452
+ */
453
+ export function utimesSync(path, atime, mtime) {
454
+ const fd = openSync.call(this, path, 'r+');
455
+ futimesSync.call(this, fd, atime, mtime);
456
+ closeSync.call(this, fd);
457
+ }
458
+ utimesSync;
459
+ /**
460
+ * Change file timestamps of the file referenced by the supplied path.
461
+ */
462
+ export function lutimesSync(path, atime, mtime) {
463
+ const fd = lopenSync.call(this, path, 'r+');
464
+ futimesSync.call(this, fd, atime, mtime);
465
+ closeSync.call(this, fd);
466
+ }
467
+ lutimesSync;
468
+ export function realpathSync(path, options) {
469
+ const encoding = typeof options == 'string' ? options : (options?.encoding ?? 'utf8');
470
+ path = normalizePath(path);
471
+ const { fullPath } = _sync.resolve(this, path);
472
+ if (encoding == 'utf8' || encoding == 'utf-8')
473
+ return fullPath;
474
+ const buf = Buffer.from(fullPath, 'utf-8');
475
+ if (encoding == 'buffer')
476
+ return buf;
477
+ return buf.toString(encoding);
478
+ }
479
+ realpathSync;
480
+ export function accessSync(path, mode = 0o600) {
481
+ if (!checkAccess)
482
+ return;
483
+ if (!hasAccess(this, statSync.call(this, path), mode)) {
484
+ throw new Exception(Errno.EACCES);
485
+ }
486
+ }
487
+ accessSync;
488
+ /**
489
+ * Synchronous `rm`. Removes files or directories (recursively).
490
+ * @param path The path to the file or directory to remove.
491
+ */
492
+ export function rmSync(path, options) {
493
+ path = normalizePath(path);
494
+ let stats;
495
+ try {
496
+ stats = lstatSync.bind(this)(path);
497
+ }
498
+ catch (error) {
499
+ if (error.code != 'ENOENT' || !options?.force)
500
+ throw error;
501
+ }
502
+ if (!stats)
503
+ return;
504
+ switch (stats.mode & constants.S_IFMT) {
505
+ case constants.S_IFDIR:
506
+ if (options?.recursive) {
507
+ for (const entry of readdirSync.call(this, path)) {
508
+ rmSync.call(this, join(path, entry), options);
509
+ }
510
+ }
511
+ rmdirSync.call(this, path);
512
+ break;
513
+ case constants.S_IFREG:
514
+ case constants.S_IFLNK:
515
+ case constants.S_IFBLK:
516
+ case constants.S_IFCHR:
517
+ unlinkSync.call(this, path);
518
+ break;
519
+ case constants.S_IFIFO:
520
+ case constants.S_IFSOCK:
521
+ default:
522
+ throw UV('ENOSYS', 'rm', path);
523
+ }
524
+ }
525
+ rmSync;
526
+ export function mkdtempSync(prefix, options) {
527
+ const encoding = typeof options === 'object' ? options?.encoding : options || 'utf8';
528
+ const path = _tempDirName(prefix);
529
+ mkdirSync.call(this, path);
530
+ return encoding == 'buffer' ? Buffer.from(path) : path;
531
+ }
532
+ mkdtempSync;
533
+ /**
534
+ * Returns a disposable object whose `path` property holds the created directory path.
535
+ * When the object is disposed, the directory and its contents will be removed if it still exists.
536
+ * If the directory cannot be deleted, disposal will throw an error.
537
+ * The object has a `remove()` method which will perform the same task.
538
+ * @todo Add `satisfies` and maybe change return type once @types/node adds this.
539
+ */
540
+ export function mkdtempDisposableSync(prefix, options) {
541
+ const path = _tempDirName(prefix);
542
+ mkdirSync.call(this, path);
543
+ const remove = () => rmSync(path, { recursive: true, force: true });
544
+ return { path, remove, [Symbol.dispose]: remove };
545
+ }
546
+ /**
547
+ * Synchronous `copyFile`. Copies a file.
548
+ * @param flags Optional flags for the copy operation. Currently supports these flags:
549
+ * - `fs.constants.COPYFILE_EXCL`: If the destination file already exists, the operation fails.
550
+ */
551
+ export function copyFileSync(source, destination, flags) {
552
+ source = normalizePath(source);
553
+ destination = normalizePath(destination);
554
+ if (flags && flags & constants.COPYFILE_EXCL && existsSync(destination))
555
+ throw UV('EEXIST', 'copyFile', destination);
556
+ writeFileSync.call(this, destination, readFileSync(source));
557
+ emitChange(this, 'rename', destination.toString());
558
+ }
559
+ copyFileSync;
560
+ /**
561
+ * Synchronous `readv`. Reads from a file descriptor into multiple buffers.
562
+ * @param fd The file descriptor.
563
+ * @param buffers An array of Uint8Array buffers.
564
+ * @param position The position in the file where to begin reading.
565
+ * @returns The number of bytes read.
566
+ */
567
+ export function readvSync(fd, buffers, position) {
568
+ const file = fromFD(this, fd);
569
+ let bytesRead = 0;
570
+ for (const buffer of buffers) {
571
+ bytesRead += file.readSync(buffer, 0, buffer.byteLength, position + bytesRead);
572
+ }
573
+ return bytesRead;
574
+ }
575
+ readvSync;
576
+ /**
577
+ * Synchronous `writev`. Writes from multiple buffers into a file descriptor.
578
+ * @param fd The file descriptor.
579
+ * @param buffers An array of Uint8Array buffers.
580
+ * @param position The position in the file where to begin writing.
581
+ * @returns The number of bytes written.
582
+ */
583
+ export function writevSync(fd, buffers, position) {
584
+ const file = fromFD(this, fd);
585
+ let bytesWritten = 0;
586
+ for (const buffer of buffers) {
587
+ bytesWritten += file.writeSync(new Uint8Array(buffer.buffer), 0, buffer.byteLength, position + bytesWritten);
588
+ }
589
+ return bytesWritten;
590
+ }
591
+ writevSync;
592
+ /**
593
+ * Synchronous `opendir`. Opens a directory.
594
+ * @param path The path to the directory.
595
+ * @param options Options for opening the directory.
596
+ * @returns A `Dir` object representing the opened directory.
597
+ * @todo Handle options
598
+ */
599
+ export function opendirSync(path, options) {
600
+ path = normalizePath(path);
601
+ return new Dir(path, this);
602
+ }
603
+ opendirSync;
604
+ /**
605
+ * Synchronous `cp`. Recursively copies a file or directory.
606
+ * @param source The source file or directory.
607
+ * @param destination The destination file or directory.
608
+ * @param opts Options for the copy operation. Currently supports these options from Node.js 'fs.cpSync':
609
+ * - `dereference`: Dereference symbolic links. *(unconfirmed)*
610
+ * - `errorOnExist`: Throw an error if the destination file or directory already exists.
611
+ * - `filter`: A function that takes a source and destination path and returns a boolean, indicating whether to copy `source` element.
612
+ * - `force`: Overwrite the destination if it exists, and overwrite existing readonly destination files. *(unconfirmed)*
613
+ * - `preserveTimestamps`: Preserve file timestamps.
614
+ * - `recursive`: If `true`, copies directories recursively.
615
+ */
616
+ export function cpSync(source, destination, opts) {
617
+ source = normalizePath(source);
618
+ destination = normalizePath(destination);
619
+ const srcStats = lstatSync.call(this, source); // Use lstat to follow symlinks if not dereferencing
620
+ if (opts?.errorOnExist && existsSync.call(this, destination))
621
+ throw UV('EEXIST', 'cp', destination);
622
+ switch (srcStats.mode & constants.S_IFMT) {
623
+ case constants.S_IFDIR:
624
+ if (!opts?.recursive)
625
+ throw UV('EISDIR', 'cp', source);
626
+ mkdirSync.call(this, destination, { recursive: true }); // Ensure the destination directory exists
627
+ for (const dirent of readdirSync.call(this, source, { withFileTypes: true })) {
628
+ if (opts.filter && !opts.filter(join(source, dirent.name), join(destination, dirent.name))) {
629
+ continue; // Skip if the filter returns false
630
+ }
631
+ cpSync.call(this, join(source, dirent.name), join(destination, dirent.name), opts);
632
+ }
633
+ break;
634
+ case constants.S_IFREG:
635
+ case constants.S_IFLNK:
636
+ copyFileSync.call(this, source, destination);
637
+ break;
638
+ case constants.S_IFBLK:
639
+ case constants.S_IFCHR:
640
+ case constants.S_IFIFO:
641
+ case constants.S_IFSOCK:
642
+ default:
643
+ throw UV('ENOSYS', 'cp', source);
644
+ }
645
+ // Optionally preserve timestamps
646
+ if (opts?.preserveTimestamps) {
647
+ utimesSync.call(this, destination, srcStats.atime, srcStats.mtime);
648
+ }
649
+ }
650
+ cpSync;
651
+ export function statfsSync(path, options) {
652
+ path = normalizePath(path);
653
+ const { fs } = resolveMount(path, this);
654
+ return _statfs(fs, options?.bigint);
655
+ }
656
+ export function globSync(pattern, options = {}) {
657
+ pattern = Array.isArray(pattern) ? pattern : [pattern];
658
+ const { cwd = '/', withFileTypes = false, exclude = () => false } = options;
659
+ // Escape special characters in pattern
660
+ const regexPatterns = pattern.map(globToRegex);
661
+ const results = [];
662
+ function recursiveList(dir) {
663
+ const entries = readdirSync(dir, { withFileTypes, encoding: 'utf8' });
664
+ for (const entry of entries) {
665
+ const fullPath = withFileTypes ? join(entry.parentPath, entry.name) : dir + '/' + entry;
666
+ if (typeof exclude != 'function' ? exclude.some(p => matchesGlob(p, fullPath)) : exclude((withFileTypes ? entry : fullPath)))
667
+ continue;
668
+ /**
669
+ * @todo is the pattern.source check correct?
670
+ */
671
+ if (statSync(fullPath).isDirectory() && regexPatterns.some(pattern => pattern.source.includes('.*'))) {
672
+ recursiveList(fullPath);
673
+ }
674
+ if (regexPatterns.some(pattern => pattern.test(fullPath.replace(/^\/+/g, '')))) {
675
+ results.push(withFileTypes ? entry : fullPath.replace(/^\/+/g, ''));
676
+ }
677
+ }
678
+ }
679
+ recursiveList(cwd);
680
+ return results;
681
+ }
682
+ globSync;
@@ -0,0 +1,21 @@
1
+ import type * as fs from 'node:fs';
2
+ /**
3
+ * @hidden
4
+ */
5
+ export type NodeReaddirOptions = {
6
+ withFileTypes?: boolean;
7
+ recursive?: boolean;
8
+ encoding?: BufferEncoding | 'buffer' | null;
9
+ } | BufferEncoding | 'buffer' | null;
10
+ /**
11
+ * Notes on omissions and exclusions:
12
+ * - `__promisify__` is omitted since it is type metadata
13
+ * - `native` is omitted since zenfs isn't native
14
+ * @internal @hidden
15
+ */
16
+ export type NodeFS = {
17
+ [K in keyof typeof fs]: (typeof fs)[K] extends (...args: any[]) => any ? // Some kind of wizardry: by using a union with a regular function, overloads are preserved but the properties disappear.
18
+ (typeof fs)[K] | ((...args: any[]) => any) : (typeof fs)[K] extends object ? Omit<(typeof fs)[K], '__promisify__' | 'native'> : (typeof fs)[K];
19
+ };
20
+ /** Helper union @hidden */
21
+ export type GlobOptionsU = fs.GlobOptionsWithFileTypes | fs.GlobOptionsWithoutFileTypes | fs.GlobOptions;