@zenfs/core 2.6.2 → 2.6.4

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 (64) hide show
  1. package/README.md +1 -1
  2. package/dist/backends/single_buffer.js +34 -11
  3. package/dist/context.js +1 -0
  4. package/dist/internal/contexts.d.ts +3 -1
  5. package/dist/internal/contexts.js +11 -1
  6. package/dist/internal/inode.d.ts +2 -0
  7. package/dist/internal/inode.js +2 -0
  8. package/dist/internal/rpc.d.ts +4 -4
  9. package/dist/node/async.d.ts +11 -1
  10. package/dist/node/async.js +14 -35
  11. package/dist/node/index.d.ts +1 -0
  12. package/dist/node/index.js +1 -0
  13. package/dist/node/promises.d.ts +17 -3
  14. package/dist/node/promises.js +32 -16
  15. package/dist/node/stats.d.ts +12 -0
  16. package/dist/node/stats.js +35 -6
  17. package/dist/node/sync.d.ts +39 -11
  18. package/dist/node/sync.js +41 -17
  19. package/dist/node/utf8stream.d.ts +99 -0
  20. package/dist/node/utf8stream.js +690 -0
  21. package/dist/utils.d.ts +10 -0
  22. package/dist/utils.js +17 -0
  23. package/dist/vfs/shared.js +9 -7
  24. package/package.json +14 -10
  25. package/scripts/test.js +15 -8
  26. package/tests/backend/single-buffer-rotate.worker.js +19 -0
  27. package/tests/backend/single-buffer.test.ts +106 -0
  28. package/tests/common/context.test.ts +38 -0
  29. package/tests/common/glob.test.ts +86 -1
  30. package/tests/common/utf8stream.test.ts +164 -0
  31. package/tests/common.ts +4 -2
  32. package/tests/fetch/fetch.ts +1 -1
  33. package/tests/fetch/run.sh +1 -1
  34. package/tests/fs/append.test.ts +1 -1
  35. package/tests/fs/concurrency.test.ts +1 -1
  36. package/tests/fs/dir.test.ts +1 -1
  37. package/tests/fs/directory.test.ts +3 -3
  38. package/tests/fs/errors.test.ts +1 -1
  39. package/tests/fs/exists.test.ts +3 -3
  40. package/tests/fs/links.test.ts +5 -5
  41. package/tests/fs/open.test.ts +5 -5
  42. package/tests/fs/permissions.test.ts +5 -5
  43. package/tests/fs/read.test.ts +3 -3
  44. package/tests/fs/readFile.test.ts +2 -2
  45. package/tests/fs/rename.test.ts +5 -5
  46. package/tests/fs/scaling.test.ts +1 -1
  47. package/tests/fs/stat.test.ts +32 -3
  48. package/tests/fs/streams.test.ts +1 -1
  49. package/tests/fs/tempdir.test.ts +1 -1
  50. package/tests/fs/times.test.ts +2 -2
  51. package/tests/fs/truncate.test.ts +1 -1
  52. package/tests/fs/watch.test.ts +1 -1
  53. package/tests/fs/write.test.ts +2 -2
  54. package/tests/fs/xattr.test.ts +1 -1
  55. package/tests/{native/setup.ts → native-setup.ts} +5 -5
  56. package/tests/setup/context.ts +1 -1
  57. package/tests/setup/cow.ts +1 -1
  58. package/tests/setup/index.ts +1 -1
  59. package/tests/setup/memory.ts +1 -1
  60. package/tests/setup/port.ts +1 -1
  61. package/tests/setup/single-buffer.ts +1 -1
  62. package/tests/setup.ts +1 -1
  63. package/tests/tsconfig.json +2 -1
  64. package/tests/native/run.sh +0 -3
package/dist/node/sync.js CHANGED
@@ -54,10 +54,11 @@ import { Buffer } from 'buffer';
54
54
  import { Errno, Exception, setUVMessage, UV } from 'kerium';
55
55
  import { encodeUTF8 } from 'utilium';
56
56
  import * as constants from '../constants.js';
57
+ import { contextOf } from '../internal/contexts.js';
57
58
  import { wrap } from '../internal/error.js';
58
59
  import { hasAccess, isDirectory } from '../internal/inode.js';
59
- import { dirname, join, matchesGlob, resolve } from '../path.js';
60
- import { _tempDirName, globToRegex, normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '../utils.js';
60
+ import { dirname, join, matchesGlob, relative, resolve } from '../path.js';
61
+ import { _isNoEntry, _tempDirName, globToRegex, normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '../utils.js';
61
62
  import { checkAccess } from '../vfs/config.js';
62
63
  import { deleteFD, fromFD, toFD } from '../vfs/file.js';
63
64
  import * as flags from '../vfs/flags.js';
@@ -88,12 +89,28 @@ export function existsSync(path) {
88
89
  }
89
90
  existsSync;
90
91
  export function statSync(path, options) {
91
- const stats = _sync.stat.call(this, path, false);
92
+ let stats;
93
+ try {
94
+ stats = _sync.stat.call(this, path, false);
95
+ }
96
+ catch (e) {
97
+ if (options?.throwIfNoEntry === false && _isNoEntry(e))
98
+ return;
99
+ throw e;
100
+ }
92
101
  return options?.bigint ? new BigIntStats(stats) : new Stats(stats);
93
102
  }
94
103
  statSync;
95
104
  export function lstatSync(path, options) {
96
- const stats = _sync.stat.call(this, path, true);
105
+ let stats;
106
+ try {
107
+ stats = _sync.stat.call(this, path, true);
108
+ }
109
+ catch (e) {
110
+ if (options?.throwIfNoEntry === false && _isNoEntry(e))
111
+ return;
112
+ throw e;
113
+ }
97
114
  return options?.bigint ? new BigIntStats(stats) : new Stats(stats);
98
115
  }
99
116
  lstatSync;
@@ -677,8 +694,10 @@ export function statfsSync(path, options) {
677
694
  }
678
695
  export function globSync(pattern, options = {}) {
679
696
  pattern = Array.isArray(pattern) ? pattern : [pattern];
680
- const { cwd = '/', withFileTypes = false, exclude = () => false } = options;
681
- const normalizedPatterns = pattern.map(p => p.replace(/^\/+/g, ''));
697
+ const $ = contextOf(this);
698
+ const { cwd = $.pwd, withFileTypes = false, exclude = () => false, followSymlinks = false } = options;
699
+ const base = resolve.call($, cwd instanceof URL ? cwd.pathname : cwd);
700
+ const normalizedPatterns = pattern.map(p => (p.startsWith('/') ? relative.call($, base, p) : p));
682
701
  const hasGlobStar = normalizedPatterns.some(p => p.includes('**'));
683
702
  const patternBases = normalizedPatterns.map(p => {
684
703
  const firstGlob = p.search(/[*?[\]{]/);
@@ -688,25 +707,30 @@ export function globSync(pattern, options = {}) {
688
707
  return lastSlash === -1 ? '' : p.slice(0, lastSlash);
689
708
  });
690
709
  const regexPatterns = normalizedPatterns.map(globToRegex);
710
+ function shouldDescend(path, relativePath) {
711
+ const isNamed = patternBases.some(base => relativePath === base || base.startsWith(relativePath + '/'));
712
+ const inScope = hasGlobStar || isNamed;
713
+ const stats = lstatSync.call($, path);
714
+ if (!stats.isSymbolicLink())
715
+ return inScope && stats.isDirectory();
716
+ return inScope && (followSymlinks || isNamed) && !!statSync.call($, path, { throwIfNoEntry: false })?.isDirectory();
717
+ }
691
718
  const results = [];
692
719
  function recursiveList(dir) {
693
- const entries = readdirSync(dir, { withFileTypes, encoding: 'utf8' });
720
+ const entries = readdirSync.call($, dir, { withFileTypes, encoding: 'utf8' });
694
721
  for (const entry of entries) {
695
722
  const fullPath = join(dir, withFileTypes ? entry.name : entry);
696
- if (typeof exclude != 'function' ? exclude.some(p => matchesGlob(p, fullPath)) : exclude((withFileTypes ? entry : fullPath)))
723
+ const relPath = relative.call($, base, fullPath);
724
+ if (typeof exclude != 'function' ? exclude.some(p => matchesGlob(p, relPath)) : exclude((withFileTypes ? entry : relPath)))
697
725
  continue;
698
- const relativePath = fullPath.replace(/^\/+/g, '');
699
- if (statSync(fullPath).isDirectory()) {
700
- if (hasGlobStar || patternBases.some(base => relativePath === base || base.startsWith(relativePath + '/'))) {
701
- recursiveList(fullPath);
702
- }
703
- }
704
- if (regexPatterns.some(rx => rx.test(relativePath))) {
705
- results.push(withFileTypes ? entry : relativePath);
726
+ if (shouldDescend(fullPath, relPath))
727
+ recursiveList(fullPath);
728
+ if (regexPatterns.some(rx => rx.test(relPath))) {
729
+ results.push(withFileTypes ? entry : relPath);
706
730
  }
707
731
  }
708
732
  }
709
- recursiveList(cwd instanceof URL ? cwd.pathname : cwd);
733
+ recursiveList(base);
710
734
  return results;
711
735
  }
712
736
  globSync;
@@ -0,0 +1,99 @@
1
+ import { Buffer } from 'buffer';
2
+ import { EventEmitter } from 'eventemitter3';
3
+ import type { EventEmitter as NodeEventEmitter } from 'node:events';
4
+ import type * as fs from 'node:fs';
5
+ import { type FSContext } from '../internal/contexts.js';
6
+ interface FS {
7
+ open(path: string, flags: string, mode: fs.Mode, cb: (err: Error | null, fd: number) => void): void;
8
+ openSync(path: string, flags: string, mode: fs.Mode): number;
9
+ close(fd: number, cb: (err: Error | null) => void): void;
10
+ write(fd: number, data: Buffer, cb: (err: Error | null, n: number) => void): void;
11
+ write(fd: number, data: string, encoding: BufferEncoding, cb: (err: Error | null, n: number) => void): void;
12
+ writeSync(fd: number, data: Buffer): number;
13
+ writeSync(fd: number, data: string, encoding: BufferEncoding): number;
14
+ fsync(fd: number, cb: (err: Error | null) => void): void;
15
+ fsyncSync(fd: number): void;
16
+ mkdir(path: string, options: {
17
+ recursive: true;
18
+ }, cb: (err: Error | null) => void): void;
19
+ mkdirSync(path: string, options: {
20
+ recursive: true;
21
+ }): void;
22
+ }
23
+ declare const kUtf8StreamFS: unique symbol;
24
+ /**
25
+ * An optimized UTF-8 stream writer that allows for flushing all of the internal buffering on demand.
26
+ */
27
+ export declare class Utf8Stream extends EventEmitter<fs.Utf8StreamEventMap> implements NodeEventEmitter, fs.Utf8Stream {
28
+ #private;
29
+ ['constructor']: typeof Utf8Stream;
30
+ static [kUtf8StreamFS]: FS;
31
+ /** @hidden @internal */
32
+ static _withContext(ctx: FSContext): typeof Utf8Stream;
33
+ constructor(options?: fs.Utf8StreamOptions);
34
+ /**
35
+ * When `contentMode` is `utf8`, `data` must be a string. When it is `buffer`, `data` must be a `Buffer`.
36
+ * @returns Whether the internal buffer is below the high water mark
37
+ */
38
+ write(data: string | Buffer): boolean;
39
+ /**
40
+ * Writes the current buffer to the file if a write was not in progress.
41
+ * Does nothing if `minLength` is zero or if it is already writing.
42
+ */
43
+ flush(cb?: ((err: Error | null) => void) | null): void;
44
+ /**
45
+ * Flushes the buffered data synchronously. This is a costly operation.
46
+ */
47
+ flushSync(): void;
48
+ /**
49
+ * Reopen the file in place, useful for log rotation.
50
+ */
51
+ reopen(file?: fs.PathLike): void;
52
+ /**
53
+ * Close the stream gracefully, flushing the internal buffer before closing.
54
+ */
55
+ end(): void;
56
+ /**
57
+ * Close the stream immediately, without flushing the internal buffer.
58
+ */
59
+ destroy(): void;
60
+ /** The mode of the file that is being written to */
61
+ get mode(): fs.Mode;
62
+ /** The file that is being written to */
63
+ get file(): string;
64
+ /** The file descriptor that is being written to */
65
+ get fd(): number;
66
+ /** The minimum length of the internal buffer that is required to be full before flushing */
67
+ get minLength(): number;
68
+ /**
69
+ * The maximum length of the internal buffer.
70
+ * If a write would cause the buffer to exceed this, the data is dropped and a `drop` event is emitted with it.
71
+ */
72
+ get maxLength(): number;
73
+ /** Whether the stream is currently writing data to the file */
74
+ get writing(): boolean;
75
+ /** Whether the stream is writing synchronously or asynchronously */
76
+ get sync(): boolean;
77
+ /** Whether the stream performs a `fsyncSync` after every write */
78
+ get fsync(): boolean;
79
+ /** Whether the stream is appending to the file or truncating it */
80
+ get append(): boolean;
81
+ /** The number of milliseconds between flushes. `0` means no periodic flushes are performed. */
82
+ get periodicFlush(): number;
83
+ /** The type of data that can be written to the stream */
84
+ get contentMode(): 'utf8' | 'buffer';
85
+ /** Whether the directory for `file` is created if it does not exist */
86
+ get mkdir(): boolean;
87
+ [Symbol.dispose](): void;
88
+ on<T extends keyof fs.Utf8StreamEventMap>(event: T, fn: (...args: fs.Utf8StreamEventMap[T]) => void, context?: any): this;
89
+ addListener<T extends keyof fs.Utf8StreamEventMap>(event: T, fn: (...args: fs.Utf8StreamEventMap[T]) => void, context?: any): this;
90
+ once<T extends keyof fs.Utf8StreamEventMap>(event: T, fn: (...args: fs.Utf8StreamEventMap[T]) => void, context?: any): this;
91
+ off<T extends keyof fs.Utf8StreamEventMap>(event: T, fn?: (...args: any[]) => void, context?: any, once?: boolean): this;
92
+ removeListener<T extends keyof fs.Utf8StreamEventMap>(event: T, fn?: (...args: any[]) => void, context?: any, once?: boolean): this;
93
+ setMaxListeners(): never;
94
+ getMaxListeners(): never;
95
+ prependListener(): never;
96
+ prependOnceListener(): never;
97
+ rawListeners(): never;
98
+ }
99
+ export {};