@zenfs/core 0.9.6 → 0.9.7

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 (56) hide show
  1. package/dist/ApiError.d.ts +4 -3
  2. package/dist/ApiError.js +1 -1
  3. package/dist/backends/AsyncStore.d.ts +3 -2
  4. package/dist/backends/AsyncStore.js +12 -5
  5. package/dist/backends/InMemory.d.ts +1 -1
  6. package/dist/backends/Index.d.ts +7 -10
  7. package/dist/backends/Index.js +7 -5
  8. package/dist/backends/Overlay.js +1 -1
  9. package/dist/backends/SyncStore.d.ts +6 -6
  10. package/dist/backends/SyncStore.js +4 -4
  11. package/dist/backends/backend.d.ts +5 -4
  12. package/dist/backends/backend.js +2 -2
  13. package/dist/browser.min.js +4 -4
  14. package/dist/browser.min.js.map +3 -3
  15. package/dist/config.d.ts +1 -1
  16. package/dist/config.js +2 -2
  17. package/dist/emulation/async.d.ts +76 -77
  18. package/dist/emulation/async.js +42 -42
  19. package/dist/emulation/dir.js +6 -5
  20. package/dist/emulation/promises.d.ts +106 -102
  21. package/dist/emulation/promises.js +61 -65
  22. package/dist/emulation/shared.d.ts +1 -7
  23. package/dist/emulation/shared.js +1 -1
  24. package/dist/emulation/streams.js +3 -2
  25. package/dist/emulation/sync.d.ts +71 -64
  26. package/dist/emulation/sync.js +39 -40
  27. package/dist/file.d.ts +4 -4
  28. package/dist/file.js +7 -5
  29. package/dist/filesystem.d.ts +1 -1
  30. package/dist/filesystem.js +3 -0
  31. package/dist/mutex.js +2 -2
  32. package/dist/stats.d.ts +7 -7
  33. package/dist/stats.js +50 -10
  34. package/dist/utils.d.ts +5 -5
  35. package/dist/utils.js +4 -3
  36. package/package.json +3 -3
  37. package/readme.md +2 -2
  38. package/src/ApiError.ts +3 -1
  39. package/src/backends/AsyncStore.ts +14 -8
  40. package/src/backends/Index.ts +14 -10
  41. package/src/backends/Overlay.ts +3 -3
  42. package/src/backends/SyncStore.ts +8 -8
  43. package/src/backends/backend.ts +7 -5
  44. package/src/config.ts +5 -5
  45. package/src/emulation/async.ts +188 -196
  46. package/src/emulation/dir.ts +6 -6
  47. package/src/emulation/promises.ts +181 -173
  48. package/src/emulation/shared.ts +2 -9
  49. package/src/emulation/streams.ts +9 -8
  50. package/src/emulation/sync.ts +159 -159
  51. package/src/file.ts +11 -9
  52. package/src/filesystem.ts +11 -7
  53. package/src/mutex.ts +3 -3
  54. package/src/stats.ts +32 -23
  55. package/src/utils.ts +10 -9
  56. package/tsconfig.json +2 -1
@@ -6,7 +6,7 @@ import { normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '.
6
6
  import * as constants from './constants.js';
7
7
  import { Dir, Dirent } from './dir.js';
8
8
  import { dirname, join, parse } from './path.js';
9
- import { cred, fd2file, fdMap, fixError, getFdForFile, mounts, resolveMount } from './shared.js';
9
+ import { cred, fd2file, fdMap, file2fd, fixError, mounts, resolveMount } from './shared.js';
10
10
  import { ReadStream, WriteStream } from './streams.js';
11
11
  export * as constants from './constants.js';
12
12
  export class FileHandle {
@@ -57,6 +57,7 @@ export class FileHandle {
57
57
  * @param len If not specified, defaults to `0`.
58
58
  */
59
59
  truncate(len) {
60
+ len || (len = 0);
60
61
  if (len < 0) {
61
62
  throw new ApiError(ErrorCode.EINVAL);
62
63
  }
@@ -80,7 +81,7 @@ export class FileHandle {
80
81
  * If `mode` is a string, it is parsed as an octal integer.
81
82
  * If `flag` is not supplied, the default of `'a'` is used.
82
83
  */
83
- async appendFile(data, _options) {
84
+ async appendFile(data, _options = {}) {
84
85
  const options = normalizeOptions(_options, 'utf8', 'a', 0o644);
85
86
  const flag = parseFlag(options.flag);
86
87
  if (!isAppendable(flag)) {
@@ -106,7 +107,7 @@ export class FileHandle {
106
107
  }
107
108
  return this.file.read(buffer, offset, length, position);
108
109
  }
109
- async readFile(_options) {
110
+ async readFile(_options = {}) {
110
111
  const options = normalizeOptions(_options, null, 'r', 0o444);
111
112
  const flag = parseFlag(options.flag);
112
113
  if (!isReadable(flag)) {
@@ -129,14 +130,14 @@ export class FileHandle {
129
130
  * @since v17.0.0
130
131
  * @experimental
131
132
  */
132
- readableWebStream(options) {
133
+ readableWebStream(options = {}) {
133
134
  // Note: using an arrow function to preserve `this`
134
135
  const start = async ({ close, enqueue, error }) => {
135
136
  try {
136
137
  const chunkSize = 64 * 1024, maxChunks = 1e7;
137
- let i = 0, position = 0, result;
138
- while (result.bytesRead > 0) {
139
- result = await this.read(new Uint8Array(chunkSize), 0, chunkSize, position);
138
+ let i = 0, position = 0, bytesRead = NaN;
139
+ while (bytesRead > 0) {
140
+ const result = await this.read(new Uint8Array(chunkSize), 0, chunkSize, position);
140
141
  if (!result.bytesRead) {
141
142
  close();
142
143
  return;
@@ -146,6 +147,7 @@ export class FileHandle {
146
147
  if (++i >= maxChunks) {
147
148
  throw new ApiError(ErrorCode.EFBIG, 'Too many iterations on readable stream', this.file.path, 'FileHandle.readableWebStream');
148
149
  }
150
+ bytesRead = result.bytesRead;
149
151
  }
150
152
  }
151
153
  catch (e) {
@@ -165,7 +167,7 @@ export class FileHandle {
165
167
  return opts?.bigint ? new BigIntStats(stats) : stats;
166
168
  }
167
169
  async write(data, posOrOff, lenOrEnc, position) {
168
- let buffer, offset = 0, length;
170
+ let buffer, offset, length;
169
171
  if (typeof data === 'string') {
170
172
  // Signature 1: (fd, string, [position?, [encoding?]])
171
173
  position = typeof posOrOff === 'number' ? posOrOff : null;
@@ -176,7 +178,7 @@ export class FileHandle {
176
178
  }
177
179
  else {
178
180
  // Signature 2: (fd, buffer, offset, length, position?)
179
- buffer = data;
181
+ buffer = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
180
182
  offset = posOrOff;
181
183
  length = lenOrEnc;
182
184
  position = typeof position === 'number' ? position : null;
@@ -196,7 +198,7 @@ export class FileHandle {
196
198
  * If `mode` is a string, it is parsed as an octal integer.
197
199
  * If `flag` is not supplied, the default of `'w'` is used.
198
200
  */
199
- async writeFile(data, _options) {
201
+ async writeFile(data, _options = {}) {
200
202
  const options = normalizeOptions(_options, 'utf8', 'w', 0o644);
201
203
  const flag = parseFlag(options.flag);
202
204
  if (!isWriteable(flag)) {
@@ -248,9 +250,9 @@ export class FileHandle {
248
250
  * @returns A `ReadStream` object.
249
251
  */
250
252
  createReadStream(options) {
251
- const streamOptions = {
253
+ const stream = new ReadStream({
252
254
  highWaterMark: options?.highWaterMark || 64 * 1024,
253
- encoding: options?.encoding,
255
+ encoding: options.encoding,
254
256
  read: async (size) => {
255
257
  try {
256
258
  const result = await this.read(new Uint8Array(size), 0, size, this.file.position);
@@ -261,8 +263,7 @@ export class FileHandle {
261
263
  stream.destroy(error);
262
264
  }
263
265
  },
264
- };
265
- const stream = new ReadStream(streamOptions);
266
+ });
266
267
  stream.path = this.file.path;
267
268
  return stream;
268
269
  }
@@ -356,12 +357,12 @@ export async function exists(_path) {
356
357
  }
357
358
  }
358
359
  export async function stat(path, options) {
359
- const stats = await doOp('stat', true, path, cred);
360
+ const stats = await doOp('stat', true, path.toString(), cred);
360
361
  return options?.bigint ? new BigIntStats(stats) : stats;
361
362
  }
362
363
  stat;
363
364
  export async function lstat(path, options) {
364
- const stats = await doOp('stat', false, path, cred);
365
+ const stats = await doOp('stat', false, path.toString(), cred);
365
366
  return options?.bigint ? new BigIntStats(stats) : stats;
366
367
  }
367
368
  lstat;
@@ -386,7 +387,7 @@ truncate;
386
387
  * @param path
387
388
  */
388
389
  export async function unlink(path) {
389
- return doOp('unlink', false, path, cred);
390
+ return doOp('unlink', false, path.toString(), cred);
390
391
  }
391
392
  unlink;
392
393
  /**
@@ -442,19 +443,11 @@ async function _open(_path, _flag, _mode = 0o644, resolveSymlinks) {
442
443
  * @param flags Handles the complexity of the various file modes. See its API for more details.
443
444
  * @param mode Mode to use to open the file. Can be ignored if the filesystem doesn't support permissions.
444
445
  */
445
- export async function open(path, flag, mode = 0o644) {
446
+ export async function open(path, flag = 'r', mode = 0o644) {
446
447
  const file = await _open(path, flag, mode, true);
447
- return new FileHandle(getFdForFile(file));
448
+ return new FileHandle(file2fd(file));
448
449
  }
449
450
  open;
450
- /**
451
- * Opens a file without resolving symlinks
452
- * @internal
453
- */
454
- export async function lopen(path, flag, mode = 0o644) {
455
- const file = await _open(path, flag, mode, false);
456
- return new FileHandle(getFdForFile(file));
457
- }
458
451
  /**
459
452
  * Asynchronously reads the entire contents of a file.
460
453
  */
@@ -472,13 +465,14 @@ async function _readFile(fname, flag, resolveSymlinks) {
472
465
  throw e;
473
466
  }
474
467
  }
475
- export async function readFile(filename, _options) {
468
+ export async function readFile(path, _options) {
476
469
  const options = normalizeOptions(_options, null, 'r', 0);
477
470
  const flag = parseFlag(options.flag);
478
471
  if (!isReadable(flag)) {
479
472
  throw new ApiError(ErrorCode.EINVAL, 'Flag passed must allow for reading.');
480
473
  }
481
- const data = Buffer.from(await _readFile(filename, options.flag, true));
474
+ path = path instanceof FileHandle ? path.file.path : path.toString();
475
+ const data = Buffer.from(await _readFile(path, options.flag, true));
482
476
  return options.encoding ? data.toString(options.encoding) : data;
483
477
  }
484
478
  readFile;
@@ -486,18 +480,22 @@ readFile;
486
480
  * Asynchronously writes data to a file, replacing the file if it already exists.
487
481
  *
488
482
  * The encoding option is ignored if data is a buffer.
489
- * @param filename
490
- * @param data
483
+ * @param path
484
+ * @param data Note:
491
485
  * @param _options
492
486
  * @option options encoding Defaults to `'utf8'`.
493
487
  * @option options mode Defaults to `0644`.
494
488
  * @option options flag Defaults to `'w'`.
495
489
  */
496
- export async function writeFile(filename, data, _options) {
490
+ export async function writeFile(path, data, _options) {
497
491
  const options = normalizeOptions(_options, 'utf8', 'w+', 0o644);
498
- const handle = await open(filename, options.flag, options.mode);
492
+ const handle = path instanceof FileHandle ? path : await open(path.toString(), options.flag, options.mode);
499
493
  try {
500
- await handle.writeFile(data, options);
494
+ const _data = typeof data == 'string' ? data : data;
495
+ if (typeof _data != 'string' && !(_data instanceof Uint8Array)) {
496
+ throw new ApiError(ErrorCode.EINVAL, 'Iterables and streams not supported', handle.file.path, 'writeFile');
497
+ }
498
+ await handle.writeFile(_data, options);
501
499
  }
502
500
  finally {
503
501
  await handle.close();
@@ -508,8 +506,8 @@ writeFile;
508
506
  * Asynchronously append data to a file, creating the file if
509
507
  * it not yet exists.
510
508
  */
511
- async function _appendFile(fname, data, flag, mode, resolveSymlinks) {
512
- const file = await _open(fname, flag, mode, resolveSymlinks);
509
+ async function _appendFile(path, data, flag, mode, resolveSymlinks) {
510
+ const file = await _open(path, flag, mode, resolveSymlinks);
513
511
  try {
514
512
  await file.write(data, 0, data.length, null);
515
513
  }
@@ -520,14 +518,14 @@ async function _appendFile(fname, data, flag, mode, resolveSymlinks) {
520
518
  /**
521
519
  * Asynchronously append data to a file, creating the file if it not yet
522
520
  * exists.
523
- * @param filename
521
+ * @param path
524
522
  * @param data
525
523
  * @param options
526
524
  * @option options encoding Defaults to `'utf8'`.
527
525
  * @option options mode Defaults to `0644`.
528
526
  * @option options flag Defaults to `'a'`.
529
527
  */
530
- export async function appendFile(filename, data, _options) {
528
+ export async function appendFile(path, data, _options) {
531
529
  const options = normalizeOptions(_options, 'utf8', 'a', 0o644);
532
530
  const flag = parseFlag(options.flag);
533
531
  if (!isAppendable(flag)) {
@@ -536,8 +534,8 @@ export async function appendFile(filename, data, _options) {
536
534
  if (typeof data != 'string' && !options.encoding) {
537
535
  throw new ApiError(ErrorCode.EINVAL, 'Encoding not specified');
538
536
  }
539
- const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding) : data;
540
- await _appendFile(filename, encodedData, options.flag, options.mode, true);
537
+ const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
538
+ await _appendFile(path instanceof FileHandle ? path.file.path : path.toString(), encodedData, options.flag, options.mode, true);
541
539
  }
542
540
  appendFile;
543
541
  // DIRECTORY-ONLY METHODS
@@ -546,11 +544,12 @@ appendFile;
546
544
  * @param path
547
545
  */
548
546
  export async function rmdir(path) {
549
- return doOp('rmdir', true, path, cred);
547
+ return doOp('rmdir', true, path.toString(), cred);
550
548
  }
551
549
  rmdir;
552
- export async function mkdir(path, mode) {
553
- await doOp('mkdir', true, path, normalizeMode(typeof mode == 'object' ? mode?.mode : mode, 0o777), cred);
550
+ export async function mkdir(path, options) {
551
+ await doOp('mkdir', true, path.toString(), normalizeMode(typeof options == 'object' ? options?.mode : options, 0o777), cred);
552
+ return;
554
553
  }
555
554
  mkdir;
556
555
  export async function readdir(path, options) {
@@ -582,7 +581,7 @@ readdir;
582
581
  */
583
582
  export async function link(existing, newpath) {
584
583
  newpath = normalizePath(newpath);
585
- return doOp('link', false, existing, newpath, cred);
584
+ return doOp('link', false, existing.toString(), newpath, cred);
586
585
  }
587
586
  link;
588
587
  /**
@@ -596,20 +595,17 @@ export async function symlink(target, path, type = 'file') {
596
595
  throw new ApiError(ErrorCode.EINVAL, 'Invalid symlink type: ' + type);
597
596
  }
598
597
  if (await exists(path)) {
599
- throw ApiError.With('EEXIST', path, 'symlink');
598
+ throw ApiError.With('EEXIST', path.toString(), 'symlink');
600
599
  }
601
- await writeFile(path, target);
600
+ await writeFile(path, target.toString());
602
601
  const file = await _open(path, 'r+', 0o644, false);
603
602
  await file._setType(FileType.SYMLINK);
604
603
  }
605
604
  symlink;
606
605
  export async function readlink(path, options) {
607
- const value = Buffer.from(await _readFile(path, 'r', false));
608
- const encoding = typeof options == 'object' ? options.encoding : options;
609
- if (encoding == 'buffer') {
610
- return value;
611
- }
612
- return value.toString(encoding);
606
+ const value = Buffer.from(await _readFile(path.toString(), 'r', false));
607
+ const encoding = typeof options == 'object' ? options?.encoding : options;
608
+ return encoding == 'buffer' ? value : value.toString(encoding);
613
609
  }
614
610
  readlink;
615
611
  // PROPERTY OPERATIONS
@@ -636,12 +632,12 @@ chown;
636
632
  * @param gid
637
633
  */
638
634
  export async function lchown(path, uid, gid) {
639
- const handle = await lopen(path, 'r+');
635
+ const file = await _open(path, 'r+', 0o644, false);
640
636
  try {
641
- await handle.chown(uid, gid);
637
+ await file.chown(uid, gid);
642
638
  }
643
639
  finally {
644
- await handle.close();
640
+ await file.close();
645
641
  }
646
642
  }
647
643
  lchown;
@@ -666,12 +662,12 @@ chmod;
666
662
  * @param mode
667
663
  */
668
664
  export async function lchmod(path, mode) {
669
- const handle = await lopen(path, 'r+');
665
+ const file = await _open(path, 'r+', 0o644, false);
670
666
  try {
671
- await handle.chmod(mode);
667
+ await new FileHandle(file2fd(file)).chmod(mode);
672
668
  }
673
669
  finally {
674
- await handle.close();
670
+ await file.close();
675
671
  }
676
672
  }
677
673
  lchmod;
@@ -698,12 +694,12 @@ utimes;
698
694
  * @param mtime
699
695
  */
700
696
  export async function lutimes(path, atime, mtime) {
701
- const handle = await lopen(path, 'r+');
697
+ const file = await _open(path, 'r+', 0o644, false);
702
698
  try {
703
- await handle.utimes(atime, mtime);
699
+ await file.utimes(new Date(atime), new Date(mtime));
704
700
  }
705
701
  finally {
706
- await handle.close();
702
+ await file.close();
707
703
  }
708
704
  }
709
705
  lutimes;
@@ -724,8 +720,8 @@ export async function realpath(path, options) {
724
720
  }
725
721
  }
726
722
  realpath;
727
- export function watch(filename, options) {
728
- throw ApiError.With('ENOSYS', filename, 'watch');
723
+ export function watch(filename, options = {}) {
724
+ throw ApiError.With('ENOSYS', filename.toString(), 'watch');
729
725
  }
730
726
  watch;
731
727
  /**
@@ -770,7 +766,7 @@ export async function rm(path, options) {
770
766
  }
771
767
  rm;
772
768
  export async function mkdtemp(prefix, options) {
773
- const encoding = typeof options === 'object' ? options.encoding : options || 'utf8';
769
+ const encoding = typeof options === 'object' ? options?.encoding : options || 'utf8';
774
770
  const fsName = `${prefix}${Date.now()}-${Math.random().toString(36).slice(2)}`;
775
771
  const resolvedPath = '/tmp/' + fsName;
776
772
  await mkdir(resolvedPath);
@@ -854,5 +850,5 @@ export async function cp(source, destination, opts) {
854
850
  }
855
851
  cp;
856
852
  export async function statfs(path, opts) {
857
- throw ApiError.With('ENOSYS', path, 'statfs');
853
+ throw ApiError.With('ENOSYS', path.toString(), 'statfs');
858
854
  }
@@ -4,7 +4,7 @@ import { FileSystem } from '../filesystem.js';
4
4
  export declare let cred: Cred;
5
5
  export declare function setCred(val: Cred): void;
6
6
  export declare const fdMap: Map<number, File>;
7
- export declare function getFdForFile(file: File): number;
7
+ export declare function file2fd(file: File): number;
8
8
  export declare function fd2file(fd: number): File;
9
9
  export interface MountMapping {
10
10
  [point: string]: FileSystem;
@@ -40,9 +40,3 @@ export declare function fixError<E extends Error>(e: E, paths: {
40
40
  [from: string]: string;
41
41
  }): E;
42
42
  export declare function mountMapping(mountMapping: MountMapping): void;
43
- /**
44
- * Types supports as path parameters.
45
- *
46
- * In the future, maybe support URL?
47
- */
48
- export type PathLike = string;
@@ -12,7 +12,7 @@ export function setCred(val) {
12
12
  // descriptors
13
13
  export const fdMap = new Map();
14
14
  let nextFd = 100;
15
- export function getFdForFile(file) {
15
+ export function file2fd(file) {
16
16
  const fd = nextFd++;
17
17
  fdMap.set(fd, file);
18
18
  return fd;
@@ -1,4 +1,5 @@
1
1
  import { Readable, Writable } from 'readable-stream';
2
+ import { ApiError, ErrorCode } from '../ApiError.js';
2
3
  export class ReadStream extends Readable {
3
4
  close(callback = () => null) {
4
5
  try {
@@ -7,7 +8,7 @@ export class ReadStream extends Readable {
7
8
  callback();
8
9
  }
9
10
  catch (err) {
10
- callback(err);
11
+ callback(new ApiError(ErrorCode.EIO, err.toString()));
11
12
  }
12
13
  }
13
14
  }
@@ -19,7 +20,7 @@ export class WriteStream extends Writable {
19
20
  callback();
20
21
  }
21
22
  catch (err) {
22
- callback(err);
23
+ callback(new ApiError(ErrorCode.EIO, err.toString()));
23
24
  }
24
25
  }
25
26
  }