@zenfs/core 2.5.2 → 2.5.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.
@@ -8,6 +8,7 @@ import type { Store } from './store/store.js';
8
8
  type Lock = Disposable & (() => void);
9
9
  declare const MetadataEntry_base: import("memium").StructConstructor<BufferView<any>>;
10
10
  declare class MetadataEntry extends MetadataEntry_base {
11
+ static name: string;
11
12
  /** Inode or data ID */
12
13
  accessor id: number;
13
14
  /** Reserved for 64-bit offset expansion */
@@ -25,6 +26,7 @@ declare const MetadataBlock_base: import("memium/decorators").StructFromTypedArr
25
26
  * This is done since IDs are not guaranteed to be sequential.
26
27
  */
27
28
  export declare class MetadataBlock extends MetadataBlock_base<ArrayBufferLike> {
29
+ static name: string;
28
30
  readonly ['constructor']: typeof MetadataBlock;
29
31
  private static readonly lockIndex;
30
32
  /**
@@ -57,6 +59,7 @@ declare const SuperBlock_base: import("memium/decorators").StructFromTypedArray<
57
59
  * The super block structure for a single-buffer file system
58
60
  */
59
61
  export declare class SuperBlock extends SuperBlock_base<ArrayBufferLike> {
62
+ static name: string;
60
63
  readonly ['constructor']: typeof SuperBlock;
61
64
  constructor(...args: ConstructorParameters<typeof BigUint64Array<ArrayBufferLike>>);
62
65
  /**
@@ -105,7 +105,7 @@ const { format } = new Intl.NumberFormat('en-US', {
105
105
  });
106
106
  let MetadataEntry = (() => {
107
107
  var _a, _b, _c, _d;
108
- let _classDecorators = [struct.packed('MetadataEntry')];
108
+ let _classDecorators = [struct.packed()];
109
109
  let _classDescriptor;
110
110
  let _classExtraInitializers = [];
111
111
  let _classThis;
@@ -137,8 +137,8 @@ let MetadataEntry = (() => {
137
137
  __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
138
138
  MetadataEntry = _classThis = _classDescriptor.value;
139
139
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
140
- __runInitializers(_classThis, _classExtraInitializers);
141
140
  }
141
+ static name = 'MetadataEntry';
142
142
  #id_accessor_storage = __runInitializers(this, _id_initializers, void 0);
143
143
  /** Inode or data ID */
144
144
  get id() { return this.#id_accessor_storage; }
@@ -162,6 +162,9 @@ let MetadataEntry = (() => {
162
162
  super(...arguments);
163
163
  __runInitializers(this, _size_extraInitializers);
164
164
  }
165
+ static {
166
+ __runInitializers(_classThis, _classExtraInitializers);
167
+ }
165
168
  };
166
169
  return MetadataEntry = _classThis;
167
170
  })();
@@ -180,7 +183,7 @@ const max_lock_attempts = 5;
180
183
  */
181
184
  let MetadataBlock = (() => {
182
185
  var _a, _b, _c, _d;
183
- let _classDecorators = [struct.packed('MetadataBlock')];
186
+ let _classDecorators = [struct.packed()];
184
187
  let _classDescriptor;
185
188
  let _classExtraInitializers = [];
186
189
  let _classThis;
@@ -218,7 +221,8 @@ let MetadataBlock = (() => {
218
221
  MetadataBlock = _classThis = _classDescriptor.value;
219
222
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
220
223
  }
221
- static lockIndex = offsetof(MetadataBlock, 'locked') / Int32Array.BYTES_PER_ELEMENT;
224
+ static name = 'MetadataBlock';
225
+ static lockIndex;
222
226
  #checksum_accessor_storage = __runInitializers(this, _checksum_initializers, void 0);
223
227
  /**
224
228
  * The crc32c checksum for the metadata block.
@@ -309,6 +313,8 @@ let MetadataBlock = (() => {
309
313
  return MetadataBlock = _classThis;
310
314
  })();
311
315
  export { MetadataBlock };
316
+ // workaround for https://github.com/microsoft/TypeScript/issues/61862
317
+ Object.assign(MetadataBlock, { lockIndex: offsetof(MetadataBlock, 'locked') / Int32Array.BYTES_PER_ELEMENT });
312
318
  const sb_magic = 0x62732e7a; // 'z.sb'
313
319
  /**
314
320
  * Shortcut for minor perf. bump
@@ -320,7 +326,7 @@ const usedBytes = 2;
320
326
  */
321
327
  let SuperBlock = (() => {
322
328
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
323
- let _classDecorators = [struct.packed('Superblock')];
329
+ let _classDecorators = [struct.packed()];
324
330
  let _classDescriptor;
325
331
  let _classExtraInitializers = [];
326
332
  let _classThis;
@@ -397,8 +403,8 @@ let SuperBlock = (() => {
397
403
  __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
398
404
  SuperBlock = _classThis = _classDescriptor.value;
399
405
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
400
- __runInitializers(_classThis, _classExtraInitializers);
401
406
  }
407
+ static name = 'SuperBlock';
402
408
  constructor(...args) {
403
409
  super(...args);
404
410
  __runInitializers(this, __padding_extraInitializers);
@@ -532,6 +538,9 @@ let SuperBlock = (() => {
532
538
  }
533
539
  return true;
534
540
  }
541
+ static {
542
+ __runInitializers(_classThis, _classExtraInitializers);
543
+ }
535
544
  };
536
545
  return SuperBlock = _classThis;
537
546
  })();
@@ -13,6 +13,7 @@ declare const Attributes_base: import("memium").StructConstructor<BufferView<any
13
13
  * @internal
14
14
  */
15
15
  export declare class Attributes extends Attributes_base {
16
+ static name: string;
16
17
  accessor size: number;
17
18
  get byteSize(): number;
18
19
  has(name: string): boolean;
@@ -151,6 +152,7 @@ declare const Inode_base: import("memium").StructConstructor<BufferView<any>>;
151
152
  * @internal
152
153
  */
153
154
  export declare class Inode extends Inode_base implements InodeLike {
155
+ static name: string;
154
156
  constructor(...args: ConstructorParameters<typeof BufferView> | [Readonly<Partial<InodeLike>>]);
155
157
  accessor data: number;
156
158
  /** For future use */
@@ -51,7 +51,7 @@ export const rootIno = 0;
51
51
  const maxDynamicData = 3968;
52
52
  let Attribute = (() => {
53
53
  var _a, _b;
54
- let _classDecorators = [struct.packed('Attribute')];
54
+ let _classDecorators = [struct.packed()];
55
55
  let _classDescriptor;
56
56
  let _classExtraInitializers = [];
57
57
  let _classThis;
@@ -73,8 +73,8 @@ let Attribute = (() => {
73
73
  __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
74
74
  Attribute = _classThis = _classDescriptor.value;
75
75
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
76
- __runInitializers(_classThis, _classExtraInitializers);
77
76
  }
77
+ static name = 'Attribute';
78
78
  #keySize_accessor_storage = __runInitializers(this, _keySize_initializers, void 0);
79
79
  get keySize() { return this.#keySize_accessor_storage; }
80
80
  set keySize(value) { this.#keySize_accessor_storage = value; }
@@ -112,6 +112,9 @@ let Attribute = (() => {
112
112
  super(...arguments);
113
113
  __runInitializers(this, _valueSize_extraInitializers);
114
114
  }
115
+ static {
116
+ __runInitializers(_classThis, _classExtraInitializers);
117
+ }
115
118
  };
116
119
  return Attribute = _classThis;
117
120
  })();
@@ -122,7 +125,7 @@ let Attribute = (() => {
122
125
  */
123
126
  let Attributes = (() => {
124
127
  var _a;
125
- let _classDecorators = [struct.packed('Attributes')];
128
+ let _classDecorators = [struct.packed()];
126
129
  let _classDescriptor;
127
130
  let _classExtraInitializers = [];
128
131
  let _classThis;
@@ -139,8 +142,8 @@ let Attributes = (() => {
139
142
  __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
140
143
  Attributes = _classThis = _classDescriptor.value;
141
144
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
142
- __runInitializers(_classThis, _classExtraInitializers);
143
145
  }
146
+ static name = 'Attributes';
144
147
  #size_accessor_storage = __runInitializers(this, _size_initializers, void 0);
145
148
  get size() { return this.#size_accessor_storage; }
146
149
  set size(value) { this.#size_accessor_storage = value; }
@@ -243,6 +246,9 @@ let Attributes = (() => {
243
246
  super(...arguments);
244
247
  __runInitializers(this, _size_extraInitializers);
245
248
  }
249
+ static {
250
+ __runInitializers(_classThis, _classExtraInitializers);
251
+ }
246
252
  };
247
253
  return Attributes = _classThis;
248
254
  })();
@@ -330,7 +336,7 @@ export const userModifiableFlags = 0x000380ff;
330
336
  */
331
337
  let Inode = (() => {
332
338
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
333
- let _classDecorators = [struct.packed('Inode')];
339
+ let _classDecorators = [struct.packed()];
334
340
  let _classDescriptor;
335
341
  let _classExtraInitializers = [];
336
342
  let _classThis;
@@ -437,8 +443,8 @@ let Inode = (() => {
437
443
  __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
438
444
  Inode = _classThis = _classDescriptor.value;
439
445
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
440
- __runInitializers(_classThis, _classExtraInitializers);
441
446
  }
447
+ static name = 'Inode';
442
448
  constructor(...args) {
443
449
  let data = {};
444
450
  if (typeof args[0] === 'object' && args[0] !== null && !ArrayBuffer.isView(args[0])) {
@@ -589,6 +595,9 @@ let Inode = (() => {
589
595
  this.ctimeMs = Date.now();
590
596
  return hasChanged;
591
597
  }
598
+ static {
599
+ __runInitializers(_classThis, _classExtraInitializers);
600
+ }
592
601
  };
593
602
  return Inode = _classThis;
594
603
  })();
@@ -55,7 +55,7 @@ import { Exception, rethrow, UV } from 'kerium';
55
55
  import { encodeUTF8 } from 'utilium';
56
56
  import * as constants from '../constants.js';
57
57
  import { hasAccess, InodeFlags, isDirectory } from '../internal/inode.js';
58
- import { join, matchesGlob, parse } from '../path.js';
58
+ import { join, matchesGlob } from '../path.js';
59
59
  import '../polyfills.js';
60
60
  import { _tempDirName, globToRegex, normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '../utils.js';
61
61
  import * as _async from '../vfs/async.js';
@@ -354,23 +354,12 @@ export async function exists(path) {
354
354
  }
355
355
  }
356
356
  export async function stat(path, options) {
357
- path = normalizePath(path);
358
- const { fs, path: resolved } = await _async.resolve(this, path);
359
- const $ex = { syscall: 'stat', path };
360
- const stats = await fs.stat(resolved).catch(rethrow($ex));
361
- if (checkAccess && !hasAccess(this, stats, constants.R_OK))
362
- throw UV('EACCES', $ex);
357
+ const stats = await _async.stat.call(this, path, false);
363
358
  return options?.bigint ? new BigIntStats(stats) : new Stats(stats);
364
359
  }
365
360
  stat;
366
361
  export async function lstat(path, options) {
367
- path = normalizePath(path);
368
- const $ex = { syscall: 'lstat', path };
369
- const { base, dir } = parse(path);
370
- const { fs, path: parent } = await _async.resolve(this, dir);
371
- const stats = await fs.stat(base ? join(parent, base) : parent).catch(rethrow($ex));
372
- if (checkAccess && !hasAccess(this, stats, constants.R_OK))
373
- throw UV('EACCES', $ex);
362
+ const stats = await _async.stat.call(this, path, true);
374
363
  return options?.bigint ? new BigIntStats(stats) : new Stats(stats);
375
364
  }
376
365
  lstat;
package/dist/node/sync.js CHANGED
@@ -56,7 +56,7 @@ import { encodeUTF8 } from 'utilium';
56
56
  import * as constants from '../constants.js';
57
57
  import { wrap } from '../internal/error.js';
58
58
  import { hasAccess, isDirectory } from '../internal/inode.js';
59
- import { join, matchesGlob, parse } from '../path.js';
59
+ import { join, matchesGlob } from '../path.js';
60
60
  import { _tempDirName, globToRegex, normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '../utils.js';
61
61
  import { checkAccess } from '../vfs/config.js';
62
62
  import { deleteFD, fromFD, toFD } from '../vfs/file.js';
@@ -87,27 +87,12 @@ export function existsSync(path) {
87
87
  }
88
88
  existsSync;
89
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 });
90
+ const stats = _sync.stat.call(this, path, false);
101
91
  return options?.bigint ? new BigIntStats(stats) : new Stats(stats);
102
92
  }
103
93
  statSync;
104
94
  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 });
95
+ const stats = _sync.stat.call(this, path, true);
111
96
  return options?.bigint ? new BigIntStats(stats) : new Stats(stats);
112
97
  }
113
98
  lstatSync;
package/dist/vfs/acl.d.ts CHANGED
@@ -19,12 +19,14 @@ export declare const enum Tag {
19
19
  }
20
20
  declare const Entry_base: import("memium").StructConstructor<BufferView<any>>;
21
21
  export declare class Entry extends Entry_base {
22
+ static name: string;
22
23
  accessor tag: Tag;
23
24
  accessor perm: number;
24
25
  accessor id: number;
25
26
  }
26
27
  declare const ACL_base: import("memium").StructConstructor<BufferView<any>>;
27
28
  export declare class ACL extends ACL_base {
29
+ static name: string;
28
30
  accessor version: number;
29
31
  entries: Entry[];
30
32
  constructor(...args: ConstructorParameters<typeof BufferView>);
package/dist/vfs/acl.js CHANGED
@@ -41,7 +41,7 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
41
41
  */
42
42
  import { withErrno } from 'kerium';
43
43
  import { err } from 'kerium/log';
44
- import { packed, sizeof } from 'memium';
44
+ import { sizeof } from 'memium';
45
45
  import { $from, struct, types as t } from 'memium/decorators';
46
46
  import { BufferView } from 'utilium/buffer.js';
47
47
  import { R_OK, S_IRWXG, S_IRWXO, S_IRWXU, W_OK, X_OK } from '../constants.js';
@@ -69,7 +69,7 @@ export var Tag;
69
69
  })(Tag || (Tag = {}));
70
70
  let Entry = (() => {
71
71
  var _a, _b, _c;
72
- let _classDecorators = [struct('ACL.Entry', packed)];
72
+ let _classDecorators = [struct.packed()];
73
73
  let _classDescriptor;
74
74
  let _classExtraInitializers = [];
75
75
  let _classThis;
@@ -96,8 +96,8 @@ let Entry = (() => {
96
96
  __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
97
97
  Entry = _classThis = _classDescriptor.value;
98
98
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
99
- __runInitializers(_classThis, _classExtraInitializers);
100
99
  }
100
+ static name = 'ACL.Entry';
101
101
  #tag_accessor_storage = __runInitializers(this, _tag_initializers, void 0);
102
102
  get tag() { return this.#tag_accessor_storage; }
103
103
  set tag(value) { this.#tag_accessor_storage = value; }
@@ -111,13 +111,16 @@ let Entry = (() => {
111
111
  super(...arguments);
112
112
  __runInitializers(this, _id_extraInitializers);
113
113
  }
114
+ static {
115
+ __runInitializers(_classThis, _classExtraInitializers);
116
+ }
114
117
  };
115
118
  return Entry = _classThis;
116
119
  })();
117
120
  export { Entry };
118
121
  let ACL = (() => {
119
122
  var _a;
120
- let _classDecorators = [struct.packed('ACL')];
123
+ let _classDecorators = [struct.packed()];
121
124
  let _classDescriptor;
122
125
  let _classExtraInitializers = [];
123
126
  let _classThis;
@@ -134,8 +137,8 @@ let ACL = (() => {
134
137
  __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
135
138
  ACL = _classThis = _classDescriptor.value;
136
139
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
137
- __runInitializers(_classThis, _classExtraInitializers);
138
140
  }
141
+ static name = 'ACL';
139
142
  #version_accessor_storage = __runInitializers(this, _version_initializers, void 0);
140
143
  get version() { return this.#version_accessor_storage; }
141
144
  set version(value) { this.#version_accessor_storage = value; }
@@ -151,6 +154,9 @@ let ACL = (() => {
151
154
  this.entries.push(new Entry(this.buffer, offset));
152
155
  }
153
156
  }
157
+ static {
158
+ __runInitializers(_classThis, _classExtraInitializers);
159
+ }
154
160
  };
155
161
  return ACL = _classThis;
156
162
  })();
@@ -2,6 +2,7 @@ import type { PathLike } from 'node:fs';
2
2
  import type { V_Context } from '../internal/contexts.js';
3
3
  import type { MkdirOptions, OpenOptions, ReaddirOptions, ResolvedPath } from './shared.js';
4
4
  import { type ExceptionExtra } from 'kerium';
5
+ import { type InodeLike } from '../internal/inode.js';
5
6
  import { Dirent } from './dir.js';
6
7
  import { Handle } from './file.js';
7
8
  /**
@@ -20,3 +21,4 @@ export declare function mkdir(this: V_Context, path: PathLike, options?: MkdirOp
20
21
  export declare function readdir(this: V_Context, path: PathLike, options?: ReaddirOptions): Promise<Dirent[]>;
21
22
  export declare function rename(this: V_Context, oldPath: PathLike, newPath: PathLike): Promise<void>;
22
23
  export declare function link(this: V_Context, target: PathLike, link: PathLike): Promise<void>;
24
+ export declare function stat(this: V_Context, path: PathLike, lstat: boolean): Promise<InodeLike>;
package/dist/vfs/async.js CHANGED
@@ -1,4 +1,4 @@
1
- import { setUVMessage, UV } from 'kerium';
1
+ import { rethrow, setUVMessage, UV } from 'kerium';
2
2
  import { decodeUTF8 } from 'utilium';
3
3
  import * as constants from '../constants.js';
4
4
  import { contextOf } from '../internal/contexts.js';
@@ -45,7 +45,7 @@ export async function resolve($, path, preserveSymlinks, extra) {
45
45
  const stats = await resolved.fs.stat(resolved.path).catch((e) => {
46
46
  if (e.code == 'ENOENT')
47
47
  return;
48
- throw setUVMessage(Object.assign(e, { syscall: 'stat', path: maybePath }));
48
+ throw setUVMessage(Object.assign(e, { syscall: 'stat', path: maybePath, ...extra }));
49
49
  });
50
50
  if (!stats)
51
51
  return { ...resolved, fullPath: path };
@@ -228,3 +228,20 @@ export async function link(target, link) {
228
228
  }
229
229
  return await fs.link(resolved, dst.path);
230
230
  }
231
+ export async function stat(path, lstat) {
232
+ path = normalizePath.call(this, path);
233
+ const extra = { syscall: lstat ? 'lstat' : 'stat', path };
234
+ let stats;
235
+ if (!lstat)
236
+ stats = (await resolve(this, path, false, extra)).stats;
237
+ else {
238
+ const { base, dir } = parse(path);
239
+ const { fs, path: parent } = await resolve(this, dir, false, extra);
240
+ stats = await fs.stat(base ? join(parent, base) : parent).catch(rethrow(extra));
241
+ }
242
+ if (!stats)
243
+ throw UV('ENOENT', extra);
244
+ if (checkAccess && !hasAccess(this, stats, constants.R_OK))
245
+ throw UV('EACCES', extra);
246
+ return stats;
247
+ }
@@ -3,6 +3,7 @@ import type { V_Context } from '../context.js';
3
3
  import { Inode } from '../internal/inode.js';
4
4
  declare const fsxattr_base: import("memium").StructConstructor<BufferView<any>>;
5
5
  declare class fsxattr extends fsxattr_base {
6
+ static name: string;
6
7
  /** xflags field value */
7
8
  accessor xflags: number;
8
9
  /** extsize field value */
package/dist/vfs/ioctl.js CHANGED
@@ -89,7 +89,7 @@ var XFlag;
89
89
  })(XFlag || (XFlag = {}));
90
90
  let fsxattr = (() => {
91
91
  var _a, _b, _c, _d, _e;
92
- let _classDecorators = [struct('fsxattr')];
92
+ let _classDecorators = [struct()];
93
93
  let _classDescriptor;
94
94
  let _classExtraInitializers = [];
95
95
  let _classThis;
@@ -131,8 +131,8 @@ let fsxattr = (() => {
131
131
  __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
132
132
  fsxattr = _classThis = _classDescriptor.value;
133
133
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
134
- __runInitializers(_classThis, _classExtraInitializers);
135
134
  }
135
+ static name = 'fsxattr';
136
136
  #xflags_accessor_storage = __runInitializers(this, _xflags_initializers, void 0);
137
137
  /** xflags field value */
138
138
  get xflags() { return this.#xflags_accessor_storage; }
@@ -170,6 +170,9 @@ let fsxattr = (() => {
170
170
  this.xflags |= XFlag[name];
171
171
  }
172
172
  }
173
+ static {
174
+ __runInitializers(_classThis, _classExtraInitializers);
175
+ }
173
176
  };
174
177
  return fsxattr = _classThis;
175
178
  })();
@@ -1,5 +1,6 @@
1
1
  import type { PathLike } from 'node:fs';
2
2
  import type { V_Context } from '../context.js';
3
+ import type { InodeLike } from '../internal/inode.js';
3
4
  import type { MkdirOptions, OpenOptions, ReaddirOptions, ResolvedPath } from './shared.js';
4
5
  import { type ExceptionExtra } from 'kerium';
5
6
  import { Dirent } from './dir.js';
@@ -21,3 +22,4 @@ export declare function mkdir(this: V_Context, path: PathLike, options?: MkdirOp
21
22
  export declare function readdir(this: V_Context, path: PathLike, options?: ReaddirOptions): Dirent[];
22
23
  export declare function rename(this: V_Context, oldPath: PathLike, newPath: PathLike): void;
23
24
  export declare function link(this: V_Context, target: PathLike, link: PathLike): void;
25
+ export declare function stat(this: V_Context, path: PathLike, lstat: boolean): InodeLike;
package/dist/vfs/sync.js CHANGED
@@ -32,7 +32,7 @@ export function resolve($, path, preserveSymlinks, extra) {
32
32
  return resolve($, target, preserveSymlinks, extra);
33
33
  }
34
34
  catch (e) {
35
- setUVMessage(Object.assign(e, { syscall: 'stat', path }));
35
+ setUVMessage(Object.assign(e, { syscall: 'stat', path, ...extra }));
36
36
  if (preserveSymlinks)
37
37
  throw e;
38
38
  }
@@ -47,7 +47,7 @@ export function resolve($, path, preserveSymlinks, extra) {
47
47
  catch (e) {
48
48
  if (e.code === 'ENOENT')
49
49
  return { ...resolved, fullPath: path };
50
- throw setUVMessage(Object.assign(e, { syscall: 'stat', path: maybePath }));
50
+ throw setUVMessage(Object.assign(e, { syscall: 'stat', path: maybePath, ...extra }));
51
51
  }
52
52
  if (!isSymbolicLink(stats)) {
53
53
  return { ...resolved, fullPath: maybePath, stats };
@@ -245,3 +245,26 @@ export function link(target, link) {
245
245
  }
246
246
  return fs.linkSync(resolved, dst.path);
247
247
  }
248
+ export function stat(path, lstat) {
249
+ path = normalizePath.call(this, path);
250
+ const extra = { syscall: lstat ? 'lstat' : 'stat', path };
251
+ let stats;
252
+ if (!lstat)
253
+ stats = resolve(this, path, false, extra).stats;
254
+ else {
255
+ const { base, dir } = parse(path);
256
+ const { fs, path: parent } = resolve(this, dir, false, extra);
257
+ try {
258
+ stats = fs.statSync(base ? join(parent, base) : parent);
259
+ }
260
+ catch (e) {
261
+ setUVMessage(Object.assign(e, extra));
262
+ throw e;
263
+ }
264
+ }
265
+ if (!stats)
266
+ throw UV('ENOENT', extra);
267
+ if (checkAccess && !hasAccess(this, stats, constants.R_OK))
268
+ throw UV('EACCES', extra);
269
+ return stats;
270
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenfs/core",
3
- "version": "2.5.2",
3
+ "version": "2.5.3",
4
4
  "description": "A filesystem, anywhere",
5
5
  "funding": {
6
6
  "type": "individual",
@@ -15,7 +15,7 @@
15
15
  ],
16
16
  "bin": {
17
17
  "make-index": "scripts/make-index.js",
18
- "zenfs-test": "scripts/test.js",
18
+ "zenfs-test": "scripts/test.ts",
19
19
  "zci": "scripts/ci-cli.js"
20
20
  },
21
21
  "files": [
@@ -75,7 +75,7 @@
75
75
  "buffer": "^6.0.3",
76
76
  "eventemitter3": "^5.0.1",
77
77
  "kerium": "^1.3.4",
78
- "memium": "^0.3.10",
78
+ "memium": "^0.4.0",
79
79
  "readable-stream": "^4.5.2",
80
80
  "utilium": "^2.5.0"
81
81
  },
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ // NOTE: Not compiled, use erasable TS only
2
3
  import { execSync } from 'node:child_process';
3
4
  import { existsSync, globSync, mkdirSync, rmSync } from 'node:fs';
4
5
  import { join, parse, basename } from 'node:path';
@@ -24,6 +25,7 @@ const { values: options, positionals } = parseArgs({
24
25
  inspect: { short: 'I', type: 'boolean', default: false },
25
26
  skip: { short: 's', type: 'string', multiple: true, default: [] },
26
27
  'exit-on-fail': { short: 'e', type: 'boolean' },
28
+ runs: { short: 'r', type: 'string' },
27
29
 
28
30
  // Coverage and performance
29
31
  coverage: { type: 'string', default: 'tests/.coverage' },
@@ -49,6 +51,7 @@ Behavior:
49
51
  -b, --build Run the npm build script prior to running tests
50
52
  -c, --common Also run tests not specific to any backend
51
53
  -e, --exit-on-fail If any tests suites fail, exit immediately
54
+ -r, --runs <n> Run tests n times and print average result
52
55
  -t, --test <glob> Which FS test suite(s) to run
53
56
  -f, --force Whether to use --test-force-exit
54
57
  -I, --inspect Use the inspector for debugging
@@ -104,7 +107,13 @@ if (options.report) {
104
107
  }
105
108
 
106
109
  let ci;
107
- if (options.ci) ci = await import('./ci.js');
110
+ if (options.ci) {
111
+ if (options.runs) {
112
+ console.error('Cannot use --ci with --runs');
113
+ process.exit(1);
114
+ }
115
+ ci = await import('./ci.js');
116
+ }
108
117
 
109
118
  options.verbose && options.force && console.debug('Forcing tests to exit (--test-force-exit)');
110
119
 
@@ -135,50 +144,13 @@ if (options.auto) {
135
144
  !options.quiet && console.log(`Auto-detected ${sum} test setup files`);
136
145
  }
137
146
 
138
- async function status(name) {
139
- const start = performance.now();
140
-
141
- if (options.ci) await ci.startCheck(name);
142
-
143
- const time = () => {
144
- let delta = Math.round(performance.now() - start),
145
- unit = 'ms';
146
-
147
- if (delta > 5000) {
148
- delta /= 1000;
149
- unit = 's';
150
- }
151
-
152
- return styleText('dim', `(${delta} ${unit})`);
153
- };
154
-
155
- const maybeName = options.verbose ? `: ${name}` : '';
156
-
157
- return {
158
- async pass() {
159
- if (!options.quiet) console.log(`${styleText('green', 'passed')}${maybeName} ${time()}`);
160
- if (options.ci) await ci.completeCheck(name, 'success');
161
- },
162
- async skip() {
163
- if (!options.quiet) console.log(`${styleText('yellow', 'skipped')}${maybeName} ${time()}`);
164
- if (options.ci) await ci.completeCheck(name, 'skipped');
165
- },
166
- async fail() {
167
- console.error(`${styleText(['red', 'bold'], 'failed')}${maybeName} ${time()}`);
168
- if (options.ci) await ci.completeCheck(name, 'failure');
169
- process.exitCode = 1;
170
- if (options['exit-on-fail']) process.exit();
171
- },
172
- };
173
- }
174
-
175
147
  if (!options.preserve) rmSync(options.coverage, { force: true, recursive: true });
176
148
  mkdirSync(options.coverage, { recursive: true });
177
149
 
178
150
  /**
179
151
  * Generate the command used to run the tests
180
152
  */
181
- function makeCommand(profileName, ...rest) {
153
+ function makeCommand(profileName: string, ...rest: string[]): string {
182
154
  const command = [
183
155
  'tsx --trace-deprecation',
184
156
  options.inspect ? '--inspect' : '',
@@ -196,19 +168,81 @@ function makeCommand(profileName, ...rest) {
196
168
  return command;
197
169
  }
198
170
 
199
- if (options.common) {
200
- const command = makeCommand('common', `'tests/*.test.ts' 'tests/**/!(fs)/*.test.ts'`);
171
+ function duration(ms: number) {
172
+ ms = Math.round(ms);
173
+ let unit = 'ms';
201
174
 
202
- if (!options.quiet) process.stdout.write('Running common tests...' + (options.verbose ? '\n' : ' '));
203
- const { pass, fail } = await status('Common tests');
204
- try {
205
- execSync(command, {
206
- stdio: ['ignore', options.verbose ? 'inherit' : 'ignore', 'inherit'],
207
- });
208
- await pass();
209
- } catch {
210
- await fail();
175
+ if (ms > 5000) {
176
+ ms /= 1000;
177
+ unit = 's';
211
178
  }
179
+
180
+ return ms + ' ' + unit;
181
+ }
182
+
183
+ const nRuns = Number.isSafeInteger(parseInt(options.runs)) ? parseInt(options.runs) : 1;
184
+
185
+ interface RunTestOptions {
186
+ name: string;
187
+ args: string[];
188
+ statusName?: string;
189
+ shouldSkip?(): boolean;
190
+ }
191
+
192
+ async function runTests(config: RunTestOptions) {
193
+ const statusName = config.statusName || config.name;
194
+
195
+ const command = makeCommand(config.name, ...config.args);
196
+
197
+ let totalTime = 0;
198
+ for (let i = 0; i < nRuns; i++) {
199
+ const start = performance.now();
200
+
201
+ if (options.ci) await ci.startCheck(statusName);
202
+
203
+ const time = () => styleText('dim', `(${duration(Math.round(performance.now() - start))})`);
204
+
205
+ let identText = options.verbose ? `: ${statusName}` : '';
206
+
207
+ if (nRuns != 1) identText += ` [${i + 1}/${nRuns}]`;
208
+
209
+ if (!options.quiet) {
210
+ if (options.verbose) console.log('Running tests:', config.name);
211
+ else process.stdout.write(`Running tests: ${config.name}... `);
212
+ }
213
+
214
+ if (config.shouldSkip?.()) {
215
+ if (!options.quiet) console.log(`${styleText('yellow', 'skipped')}${identText} ${time()}`);
216
+ if (options.ci) await ci.completeCheck(statusName, 'skipped');
217
+ return;
218
+ }
219
+
220
+ try {
221
+ execSync(command, {
222
+ stdio: ['ignore', options.verbose ? 'inherit' : 'ignore', 'inherit'],
223
+ });
224
+ if (!options.quiet) console.log(`${styleText('green', 'passed')}${identText} ${time()}`);
225
+ if (options.ci) await ci.completeCheck(statusName, 'success');
226
+ totalTime += performance.now() - start;
227
+ } catch {
228
+ console.error(`${styleText(['red', 'bold'], 'failed')}${identText} ${time()}`);
229
+ if (options.ci) await ci.completeCheck(statusName, 'failure');
230
+ process.exitCode = 1;
231
+ if (options['exit-on-fail']) process.exit();
232
+ return;
233
+ }
234
+ }
235
+ if (nRuns != 1) {
236
+ console.log('Average', config.name, 'time:', styleText('blueBright', duration(totalTime / nRuns)));
237
+ }
238
+ }
239
+
240
+ if (options.common) {
241
+ await runTests({
242
+ name: 'common',
243
+ args: [`'tests/*.test.ts'`, `'tests/**/!(fs)/*.test.ts'`],
244
+ statusName: 'Common tests',
245
+ });
212
246
  }
213
247
 
214
248
  const testsGlob = join(import.meta.dirname, `../tests/fs/${options.test || '*'}.test.ts`);
@@ -223,28 +257,13 @@ for (const setupFile of positionals) {
223
257
 
224
258
  const name = options['file-names'] && !options.ci ? setupFile : parse(setupFile).name;
225
259
 
226
- const command = makeCommand(name, `'${testsGlob.replaceAll("'", "\\'")}'`, process.env.CMD);
227
-
228
- if (!options.quiet) {
229
- if (options.verbose) console.log('Running tests:', name);
230
- else process.stdout.write(`Running tests: ${name}... `);
231
- }
232
-
233
- const { pass, fail, skip } = await status(name);
234
-
235
- if (basename(setupFile).startsWith('_')) {
236
- await skip();
237
- continue;
238
- }
239
-
240
- try {
241
- execSync(command, {
242
- stdio: ['ignore', options.verbose ? 'inherit' : 'ignore', 'inherit'],
243
- });
244
- await pass();
245
- } catch {
246
- await fail();
247
- }
260
+ await runTests({
261
+ name,
262
+ args: [`'${testsGlob.replaceAll("'", "\\'")}'`, process.env.CMD],
263
+ shouldSkip() {
264
+ return basename(setupFile).startsWith('_');
265
+ },
266
+ });
248
267
  }
249
268
 
250
269
  if (!options.preserve) report();