instrumentality 0.0.8 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,9 +1,7 @@
1
- ![white title](./assets/titleLight.webp)
2
-
3
-
4
1
  ## The INSTRUMENTALITY project (concept)
5
2
  A utility library for TypeScript/Node.js
6
3
 
4
+ ![white title](./assets/titleLight.webp)
7
5
 
8
6
  #
9
7
  ### What is this?
package/dist/road.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as cr from "node:crypto";
2
2
  import * as fs from "node:fs";
3
+ import * as fp from "node:fs/promises";
3
4
  import { InsErr } from "./base.ts";
4
5
  /** Subclass of {@link InsErr} that represents an error thrown from this specific module of the library */
5
6
  export declare class Err extends InsErr {
@@ -87,23 +88,11 @@ export declare abstract class Road {
87
88
  ancestorsIt(): Generator<Folder, void, unknown>;
88
89
  /** @returns An array of {@link Folder} instances representing the ancestors of the current road. */
89
90
  ancestors(): Folder[];
90
- /**
91
- * Aquires a lock for the path represented by this Road instance, preventing concurrent modifications from this and other Road instances pointing to the same path.
92
- *
93
- * @returns An object with a dispose method that releases the lock when called.
94
- * @throws If the road is immutable, a {@link Err} will be thrown.
95
- *
96
- * @remarks This method MUST be used with a `using` statement to ensure that the lock is released properly. Failing to do so WILL result in deadlocks and other concurrency issues.
97
- * Non-deterministic release is unfortunately not possible due to the nature of JavaScript's garbage collection, thus the lock must be released deterministically by the user (for which the `using` statement is a convenient way to do so).
98
- * @remarks Methods may call other methods that each acquire their own locks, and release them independently, meaning from the perspective of other instances, the lock may appear to be free even if the original method still has work to do.
99
- * To fix this, it's recommeneded to aquire a lock at the beginning and use fs/fp operations within the locked context.
100
- */
101
- protected lock(): Promise<Disposable & AsyncDisposable>;
102
- /**
103
- * Sync version of {@link lock}.
104
- * @throws If the road is currently locked by another operation as it cannot wait for the lock to be released in a synchronous context.
105
- */
106
- protected lockSync(): Disposable & AsyncDisposable;
91
+ protected reserveLock(allowConcurrent: boolean): Disposable & {
92
+ previous: Promise<void> | undefined;
93
+ };
94
+ lock(): Promise<Disposable>;
95
+ lockSync(): Disposable;
107
96
  /**
108
97
  * Watches the current entry for changes and resolves when the entry becomes accessible (i.e., exists and can be accessed).
109
98
  *
@@ -134,8 +123,8 @@ export declare abstract class Road {
134
123
  delete(): Promise<void>;
135
124
  /** Wrapper around {@link fs.rmSync} with locking. */
136
125
  deleteSync(): void;
137
- copy(into_: Folder, options_?: fs.CopyOptions): Promise<this>;
138
- copySync(into_: Folder, options_?: fs.CopySyncOptions): this;
126
+ copy(into_: Folder): Promise<this>;
127
+ copySync(into_: Folder): this;
139
128
  move(into_: Folder): Promise<void>;
140
129
  moveSync(into_: Folder): void;
141
130
  rename(newName_: string): Promise<void>;
@@ -176,11 +165,11 @@ export declare class File extends Road {
176
165
  * @returns A promise that resolves to the newly created `File` instance.
177
166
  * @throws if {@link fp.writeFile} throws.
178
167
  */
179
- static create(at_: string): Promise<File>;
168
+ static create(at_: string, data?: string | Buffer): Promise<File>;
180
169
  /** Alias for {@link File.create}. */
181
170
  static readonly mk: typeof File.create;
182
171
  /** Synchronous version of {@link File.create}. */
183
- static createSync(at_: string): File;
172
+ static createSync(at_: string, data?: string | Buffer): File;
184
173
  /** Alias for {@link File.createSync}. */
185
174
  static readonly mkSync: typeof File.createSync;
186
175
  /** The file extension of this file, including the leading dot. */
@@ -194,15 +183,13 @@ export declare class File extends Road {
194
183
  * @throws If the file can't be read due to permission issues or other filesystem errors.
195
184
  */
196
185
  read(): Promise<Buffer>;
197
- read(encoding_: BufferEncoding, flag_?: string): Promise<string>;
186
+ read(options_: Parameters<typeof fp.readFile>[1]): Promise<string>;
198
187
  readSync(): Buffer;
199
- readSync(encoding_: BufferEncoding, flag_?: string): string;
188
+ readSync(options_: Parameters<typeof fs.readFileSync>[1]): string;
189
+ itBuff(options_?: fs.ReadStreamOptions): AsyncGenerator<Buffer>;
190
+ itBuffSync(chunkSize_?: number, flags_?: string | number, mode_?: fs.Mode): Generator<Buffer>;
200
191
  sameAs(other_: File): Promise<boolean>;
201
192
  sameAsSync(other_: File): boolean;
202
- itBuff(chunkSize_?: number, flags_?: string | number, mode_?: fs.Mode): AsyncGenerator<Buffer<ArrayBuffer>, void, unknown>;
203
- itBuffSync(chunkSize_?: number, flags_?: string | number, mode_?: fs.Mode): Generator<Buffer<ArrayBuffer>, void, unknown>;
204
- itLines(chunkSize_?: number, flags_?: string | number, mode_?: fs.Mode): AsyncGenerator<string, void, unknown>;
205
- itLinesSync(chunkSize_?: number, flags_?: string | number, mode_?: fs.Mode): Generator<string, void, unknown>;
206
193
  hash(algorithm_?: string, options_?: cr.HashOptions): Promise<Buffer>;
207
194
  hash(algorithm_?: string, options_?: cr.HashOptions, encoding_?: BufferEncoding): Promise<string>;
208
195
  hashSync(algorithm_?: string, options_?: cr.HashOptions): Buffer;
@@ -246,11 +233,17 @@ export declare class Folder extends Road {
246
233
  findSync(name_: string): Road | null;
247
234
  findSync<T extends Road>(name_: string, expect_: road_t<T>): T | null;
248
235
  add<T extends Road>(name_: string, createable_: {
249
- create: (at: string) => Promise<T>;
236
+ mk: (at: string) => Promise<T>;
250
237
  }): Promise<T>;
251
238
  addSync<T extends Road>(name_: string, createable_: {
252
- createSync: (at: string) => T;
239
+ mkSync: (at: string) => T;
253
240
  }): T;
241
+ borrow<T extends Road>(createable_: {
242
+ mk: (at: string) => Promise<T>;
243
+ }, cb_: (r: T) => Promise<void> | void): Promise<void>;
244
+ borrowSync<T extends Road>(createable_: {
245
+ mkSync: (at: string) => T;
246
+ }, cb_: (r: T) => void): void;
254
247
  size(): Promise<number>;
255
248
  sizeSync(): number;
256
249
  check(): Promise<boolean>;
@@ -330,17 +323,4 @@ export declare class Socket extends UnusableRoad {
330
323
  checkSync(): boolean;
331
324
  isSocket(): this is Socket;
332
325
  }
333
- export declare function Temp<T extends Road>(createable_: {
334
- create: (at: string) => Promise<T>;
335
- }): Promise<T & Disposable & AsyncDisposable>;
336
- export declare function TempSync<T extends Road>(createable_: {
337
- createSync: (at: string) => T;
338
- }): T & Disposable & AsyncDisposable;
339
- export declare function registerToCleanup(self_: Road): void;
340
- export declare function AutoTemp<T extends Road>(createable_: {
341
- mk: (at: string) => Promise<T>;
342
- }): Promise<T & Disposable & AsyncDisposable>;
343
- export declare function AutoTempSync<T extends Road>(createable_: {
344
- mk: (at: string) => T;
345
- }, autoCleanup_: boolean): T & Disposable & AsyncDisposable;
346
326
  //# sourceMappingURL=road.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"road.d.ts","sourceRoot":"","sources":["../src/road.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"road.d.ts","sourceRoot":"","sources":["../src/road.ts"],"names":[],"mappings":"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"}
package/dist/road.js CHANGED
@@ -137,52 +137,35 @@ export class Road {
137
137
  }
138
138
  /** @returns An array of {@link Folder} instances representing the ancestors of the current road. */
139
139
  ancestors() { return [...this.ancestorsIt()]; }
140
- /**
141
- * Aquires a lock for the path represented by this Road instance, preventing concurrent modifications from this and other Road instances pointing to the same path.
142
- *
143
- * @returns An object with a dispose method that releases the lock when called.
144
- * @throws If the road is immutable, a {@link Err} will be thrown.
145
- *
146
- * @remarks This method MUST be used with a `using` statement to ensure that the lock is released properly. Failing to do so WILL result in deadlocks and other concurrency issues.
147
- * Non-deterministic release is unfortunately not possible due to the nature of JavaScript's garbage collection, thus the lock must be released deterministically by the user (for which the `using` statement is a convenient way to do so).
148
- * @remarks Methods may call other methods that each acquire their own locks, and release them independently, meaning from the perspective of other instances, the lock may appear to be free even if the original method still has work to do.
149
- * To fix this, it's recommeneded to aquire a lock at the beginning and use fs/fp operations within the locked context.
150
- */
151
- async lock() {
140
+ reserveLock(allowConcurrent) {
152
141
  if (!this.mutable)
153
142
  throw new Err(`Road to '${this.isAt}' is immutable.`);
154
143
  lockedRoads ??= new Map();
155
144
  const { promise, resolve } = Promise.withResolvers();
145
+ const isAt = this.isAt;
156
146
  const previous = lockedRoads.get(this.isAt);
147
+ if (!allowConcurrent && previous)
148
+ throw new Err(`Road to '${this.isAt}' is already locked.`);
157
149
  lockedRoads.set(this.isAt, promise);
158
- const isAt = this.isAt;
159
- const dispose = () => {
160
- resolve();
161
- if (lockedRoads.get(isAt) === promise)
162
- lockedRoads.delete(isAt);
150
+ return {
151
+ [Symbol.dispose]: () => {
152
+ resolve();
153
+ if (lockedRoads.get(isAt) === promise)
154
+ lockedRoads.delete(isAt);
155
+ },
156
+ previous,
163
157
  };
164
- await previous;
165
- return { [Symbol.dispose]: dispose, [Symbol.asyncDispose]: dispose };
166
158
  }
167
- /**
168
- * Sync version of {@link lock}.
169
- * @throws If the road is currently locked by another operation as it cannot wait for the lock to be released in a synchronous context.
170
- */
159
+ async lock() {
160
+ const l = this.reserveLock(true);
161
+ try {
162
+ await l.previous;
163
+ }
164
+ catch { }
165
+ return l;
166
+ }
171
167
  lockSync() {
172
- if (!this.mutable)
173
- throw new Err(`Road to '${this.isAt}' is immutable.`);
174
- lockedRoads ??= new Map();
175
- const { promise, resolve } = Promise.withResolvers();
176
- if (lockedRoads.has(this.isAt))
177
- throw new Err(`Road to '${this.isAt}' is already locked.`);
178
- lockedRoads.set(this.isAt, promise);
179
- const isAt = this.isAt;
180
- const dispose = () => {
181
- resolve();
182
- if (lockedRoads.get(isAt) === promise)
183
- lockedRoads.delete(isAt);
184
- };
185
- return { [Symbol.dispose]: dispose, [Symbol.asyncDispose]: dispose };
168
+ return this.reserveLock(false);
186
169
  }
187
170
  /**
188
171
  * Watches the current entry for changes and resolves when the entry becomes accessible (i.e., exists and can be accessed).
@@ -249,14 +232,14 @@ export class Road {
249
232
  using _ = this.lockSync();
250
233
  fs.rmSync(this.isAt, { recursive: true, force: true });
251
234
  }
252
- async copy(into_, options_) {
235
+ async copy(into_) {
253
236
  const newPath = into_.join(this.name);
254
- await fp.cp(this.isAt, newPath, { recursive: true, ...options_ });
237
+ await fp.cp(this.isAt, newPath, { recursive: true, force: true });
255
238
  return new this.constructor(newPath, false);
256
239
  }
257
- copySync(into_, options_) {
240
+ copySync(into_) {
258
241
  const newPath = into_.join(this.name);
259
- fs.cpSync(this.isAt, newPath, { recursive: true, ...options_ });
242
+ fs.cpSync(this.isAt, newPath, { recursive: true, force: true });
260
243
  return new this.constructor(newPath, false);
261
244
  }
262
245
  async move(into_) {
@@ -315,24 +298,24 @@ export class File extends Road {
315
298
  * @returns A promise that resolves to the newly created `File` instance.
316
299
  * @throws if {@link fp.writeFile} throws.
317
300
  */
318
- static async create(at_) {
301
+ static async create(at_, data = "") {
319
302
  try {
320
303
  await fp.access(at_, fsc.W_OK);
321
304
  }
322
305
  catch {
323
- await fp.writeFile(at_, "");
306
+ await fp.writeFile(at_, data);
324
307
  }
325
308
  return new File(at_, true);
326
309
  }
327
310
  /** Alias for {@link File.create}. */
328
311
  static mk = File.create;
329
312
  /** Synchronous version of {@link File.create}. */
330
- static createSync(at_) {
313
+ static createSync(at_, data = "") {
331
314
  try {
332
315
  fs.accessSync(at_, fs.constants.W_OK);
333
316
  }
334
317
  catch {
335
- fs.writeFileSync(at_, "");
318
+ fs.writeFileSync(at_, data);
336
319
  }
337
320
  return new File(at_, true);
338
321
  }
@@ -342,66 +325,21 @@ export class File extends Road {
342
325
  get ext() { return ph.extname(this.isAt); }
343
326
  /** The file name without its extension. */
344
327
  get noExt() { return ph.basename(this.isAt, this.ext); }
345
- async read(encoding_, flag_) {
346
- if (encoding_)
347
- return fp.readFile(this.isAt, { encoding: encoding_, flag: flag_ });
348
- else
349
- return fp.readFile(this.isAt);
350
- }
351
- readSync(encoding_, flag_) {
352
- if (encoding_)
353
- return fs.readFileSync(this.isAt, { encoding: encoding_, flag: flag_ });
354
- else
355
- return fs.readFileSync(this.isAt);
328
+ async read(options_) {
329
+ return fp.readFile(this.isAt, options_);
356
330
  }
357
- async sameAs(other_) {
358
- if (this.isAt === other_.isAt)
359
- return true;
360
- else if ((await fp.lstat(this.isAt)).size !== (await fp.lstat(other_.isAt)).size)
361
- return false;
362
- const iter1 = this.itBuff();
363
- const iter2 = other_.itBuff();
364
- while (true) {
365
- const [a, b] = await Promise.all([iter1.next(), iter2.next()]);
366
- if (a.done && b.done)
367
- return true;
368
- if (a.done !== b.done)
369
- return false;
370
- if (!a.value.equals(b.value))
371
- return false;
372
- }
331
+ readSync(options_) {
332
+ return fs.readFileSync(this.isAt, options_);
373
333
  }
374
- sameAsSync(other_) {
375
- if (this.isAt === other_.isAt)
376
- return true;
377
- else if (fs.lstatSync(this.isAt).size !== fs.lstatSync(other_.isAt).size)
378
- return false;
379
- const iter1 = this.itBuffSync();
380
- const iter2 = other_.itBuffSync();
381
- while (true) {
382
- const a = iter1.next();
383
- const b = iter2.next();
384
- if (a.done && b.done)
385
- return true;
386
- if (a.done !== b.done)
387
- return false;
388
- if (!a.value.equals(b.value))
389
- return false;
390
- }
391
- }
392
- async *itBuff(chunkSize_ = 64 * 1024, flags_ = 'r', mode_) {
393
- const fd = await fp.open(this.isAt, flags_, mode_);
334
+ async *itBuff(options_) {
335
+ const stream = fs.createReadStream(this.isAt, { ...options_, encoding: undefined });
394
336
  try {
395
- const buffer = Buffer.alloc(chunkSize_);
396
- let bytesRead;
397
- do {
398
- bytesRead = (await fd.read(buffer, 0, chunkSize_, null)).bytesRead;
399
- if (bytesRead > 0)
400
- yield Buffer.from(buffer.subarray(0, bytesRead));
401
- } while (bytesRead === chunkSize_);
337
+ for await (const chunk of stream)
338
+ yield chunk;
402
339
  }
403
340
  finally {
404
- await fd.close();
341
+ if (!stream.destroyed)
342
+ stream.destroy();
405
343
  }
406
344
  }
407
345
  *itBuffSync(chunkSize_ = 64 * 1024, flags_ = 'r', mode_) {
@@ -419,37 +357,63 @@ export class File extends Road {
419
357
  fs.closeSync(fd);
420
358
  }
421
359
  }
422
- async *itLines(chunkSize_ = 64 * 1024, flags_ = 'r', mode_) {
423
- const decoder = new TextDecoder("utf-8", { fatal: true });
424
- let carry = "";
425
- for await (const chunk of this.itBuff(chunkSize_, flags_, mode_)) {
426
- carry += decoder.decode(chunk, { stream: true });
427
- let newlineINdex;
428
- while ((newlineINdex = carry.indexOf("\n")) !== -1) {
429
- const line = carry.slice(0, newlineINdex);
430
- yield line.endsWith("\r") ? line.slice(0, -1) : line;
431
- carry = carry.slice(newlineINdex + 1);
360
+ async sameAs(other_) {
361
+ if (this.isAt === other_.isAt)
362
+ return true;
363
+ const [s1, s2] = await Promise.all([this.size(), other_.size()]);
364
+ if (s1 !== s2)
365
+ return false;
366
+ if (s1 === 0)
367
+ return true;
368
+ const iter1 = this.itBuff();
369
+ const iter2 = other_.itBuff();
370
+ try {
371
+ while (true) {
372
+ const [a, b] = await Promise.all([iter1.next(), iter2.next()]);
373
+ if (a.done && b.done)
374
+ return true;
375
+ if (a.done !== b.done)
376
+ return false;
377
+ if (!a.value.equals(b.value))
378
+ return false;
379
+ }
380
+ }
381
+ finally {
382
+ await Promise.all([iter1.return?.(undefined), iter2.return?.(undefined)]);
383
+ }
384
+ }
385
+ sameAsSync(other_) {
386
+ if (this.isAt === other_.isAt)
387
+ return true;
388
+ const [s1, s2] = [this.sizeSync(), other_.sizeSync()];
389
+ if (s1 !== s2)
390
+ return false;
391
+ if (s1 === 0)
392
+ return true;
393
+ const iter1 = this.itBuffSync();
394
+ const iter2 = other_.itBuffSync();
395
+ try {
396
+ while (true) {
397
+ const a = iter1.next();
398
+ const b = iter2.next();
399
+ if (a.done && b.done)
400
+ return true;
401
+ if (a.done !== b.done)
402
+ return false;
403
+ if (!a.value.equals(b.value))
404
+ return false;
432
405
  }
433
406
  }
434
- carry += decoder.decode();
435
- if (carry.length > 0)
436
- yield carry.endsWith("\r") ? carry.slice(0, -1) : carry;
437
- }
438
- *itLinesSync(chunkSize_ = 64 * 1024, flags_ = 'r', mode_) {
439
- const decoder = new TextDecoder("utf-8", { fatal: true });
440
- let carry = "";
441
- for (const chunk of this.itBuffSync(chunkSize_, flags_, mode_)) {
442
- carry += decoder.decode(chunk, { stream: true });
443
- let newlineINdex;
444
- while ((newlineINdex = carry.indexOf("\n")) !== -1) {
445
- const line = carry.slice(0, newlineINdex);
446
- yield line.endsWith("\r") ? line.slice(0, -1) : line;
447
- carry = carry.slice(newlineINdex + 1);
407
+ finally {
408
+ try {
409
+ iter1.return?.(undefined);
448
410
  }
411
+ catch { }
412
+ try {
413
+ iter2.return?.(undefined);
414
+ }
415
+ catch { }
449
416
  }
450
- carry += decoder.decode();
451
- if (carry.length > 0)
452
- yield carry.endsWith("\r") ? carry.slice(0, -1) : carry;
453
417
  }
454
418
  async hash(algorithm_ = "sha256", options_, encoding_) {
455
419
  const hash = cr.createHash(algorithm_, options_);
@@ -467,17 +431,19 @@ export class File extends Road {
467
431
  sizeSync() { return this.lstatSync().size; }
468
432
  async writeAtomic(data_, options_) {
469
433
  using _ = await this.lock();
470
- const temp = await Temp(File); // Don't use `using` as we won't clean it up
471
- await fp.rename(temp.isAt, this.parent().join(temp.name)); // Move temp file to the same directory as the target
472
- await fp.writeFile(temp.isAt, data_, options_); // Write data to the temp file
473
- await fp.rename(temp.isAt, this.isAt); // Replace the target file with the temp file atomically
434
+ await this.parent().borrow(File, async (tmp) => {
435
+ using _ = await tmp.lock();
436
+ await fp.writeFile(tmp.isAt, data_, options_);
437
+ await fp.rename(tmp.isAt, this.isAt);
438
+ });
474
439
  }
475
440
  writeAtomicSync(data_, options_) {
476
441
  using _ = this.lockSync();
477
- const temp = TempSync(File); // Don't use `using` as we won't clean it up
478
- fs.renameSync(temp.isAt, this.parent().join(temp.name)); // Move temp file to the same directory as the target
479
- fs.writeFileSync(temp.isAt, data_, options_); // Write data to the temp file
480
- fs.renameSync(temp.isAt, this.isAt); // Replace the target file with the temp file atomically
442
+ this.parent().borrowSync(File, tmp => {
443
+ using _ = tmp.lockSync();
444
+ fs.writeFileSync(tmp.isAt, data_, options_);
445
+ fs.renameSync(tmp.isAt, this.isAt);
446
+ });
481
447
  }
482
448
  async write(data_, options_) {
483
449
  using _ = await this.lock();
@@ -549,16 +515,11 @@ export class Folder extends Road {
549
515
  }
550
516
  async list(filter_) {
551
517
  const entries = (await fp.readdir(this.isAt, { withFileTypes: true })).map(e => new (resolveDirent(e))(this.join(e.name), false));
552
- const resolvedEntries = await Promise.all(entries);
553
- if (!filter_)
554
- return resolvedEntries;
555
- return resolvedEntries.filter(entry => filter_(entry));
518
+ return filter_ ? entries.filter(entry => filter_(entry)) : entries;
556
519
  }
557
520
  listSync(filter_) {
558
521
  const entries = fs.readdirSync(this.isAt, { withFileTypes: true }).map(e => new (resolveDirent(e))(this.join(e.name), false));
559
- if (!filter_)
560
- return entries;
561
- return entries.filter(entry => filter_(entry));
522
+ return filter_ ? entries.filter(entry => filter_(entry)) : entries;
562
523
  }
563
524
  async *walk(filter_) {
564
525
  for await (const entry of this.it()) {
@@ -604,14 +565,32 @@ export class Folder extends Road {
604
565
  }
605
566
  async add(name_, createable_) {
606
567
  const newPath = this.join(name_);
607
- await createable_.create(newPath);
568
+ await createable_.mk(newPath);
608
569
  return (await factory(newPath));
609
570
  }
610
571
  addSync(name_, createable_) {
611
572
  const newPath = this.join(name_);
612
- createable_.createSync(newPath);
573
+ createable_.mkSync(newPath);
613
574
  return factorySync(newPath);
614
575
  }
576
+ async borrow(createable_, cb_) {
577
+ const path = this.join(`instrumentality@${crypto.randomUUID()}`);
578
+ try {
579
+ await cb_(await createable_.mk(path));
580
+ }
581
+ finally {
582
+ await fp.rm(path, { recursive: true, force: true });
583
+ }
584
+ }
585
+ borrowSync(createable_, cb_) {
586
+ const path = this.join(`instrumentality@${crypto.randomUUID()}`);
587
+ try {
588
+ cb_(createable_.mkSync(path));
589
+ }
590
+ finally {
591
+ fs.rmSync(path, { recursive: true, force: true });
592
+ }
593
+ }
615
594
  async size() {
616
595
  let size = 0;
617
596
  for await (const entry of this.it())
@@ -708,7 +687,6 @@ export class SymbolicLink extends Road {
708
687
  isSymbolicLink() { return true; }
709
688
  }
710
689
  export { SymbolicLink as Symlink };
711
- here().walk(r => !r.isSymlink());
712
690
  export class UnusableRoad extends Road {
713
691
  mutable = false; // Modification will cause system issues (e.g. deleting a device file)
714
692
  async size() { return 0; }
@@ -796,90 +774,3 @@ export class Socket extends UnusableRoad {
796
774
  } }
797
775
  isSocket() { return true; }
798
776
  }
799
- export async function Temp(createable_) {
800
- let t = await createable_.create(tmp().join(`instrumentality@${cr.randomUUID()}`));
801
- return Object.assign(t, {
802
- [Symbol.dispose]() { try {
803
- t.deleteSync();
804
- }
805
- catch { } toDelete?.delete(t.isAt); finalizer?.unregister(t); },
806
- async [Symbol.asyncDispose]() { try {
807
- await t.delete();
808
- }
809
- catch { } toDelete?.delete(t.isAt); finalizer?.unregister(t); }
810
- });
811
- }
812
- export function TempSync(createable_) {
813
- let t = createable_.createSync(tmp().join(`instrumentality@${cr.randomUUID()}`));
814
- return Object.assign(t, {
815
- [Symbol.dispose]() { try {
816
- t.deleteSync();
817
- }
818
- catch { } toDelete?.delete(t.isAt); finalizer?.unregister(t); },
819
- async [Symbol.asyncDispose]() { try {
820
- await t.delete();
821
- }
822
- catch { } toDelete?.delete(t.isAt); finalizer?.unregister(t); }
823
- });
824
- }
825
- let finalizer = null;
826
- let toDelete = null;
827
- let exitHandlerRegistered = null;
828
- /**
829
- * Forcefully cleans up all files and folders registered for cleanup on exit.
830
- */
831
- function forceCleanupToDelete() {
832
- for (const path of toDelete ?? [])
833
- try {
834
- fs.rmSync(path, { force: true, recursive: true });
835
- }
836
- catch { }
837
- toDelete?.clear();
838
- toDelete = null;
839
- finalizer = null;
840
- if (exitHandlerRegistered)
841
- process.off('exit', forceCleanupToDelete);
842
- exitHandlerRegistered = false;
843
- }
844
- export function registerToCleanup(self_) {
845
- finalizer ??= new FinalizationRegistry(p => { try {
846
- fs.rmSync(p, { force: true, recursive: true });
847
- }
848
- catch { } ; toDelete?.delete(p); });
849
- toDelete ??= new Set();
850
- if (!exitHandlerRegistered) {
851
- process.once('exit', forceCleanupToDelete);
852
- exitHandlerRegistered = true;
853
- }
854
- toDelete.add(self_.isAt);
855
- finalizer.register(self_, self_.isAt, self_);
856
- }
857
- export async function AutoTemp(createable_) {
858
- let t = await createable_.mk(tmp().join(`instrumentality@${cr.randomUUID()}`));
859
- registerToCleanup(t);
860
- return Object.freeze(Object.assign(t, {
861
- [Symbol.dispose]() { try {
862
- t.deleteSync();
863
- }
864
- catch { } toDelete?.delete(t.isAt); finalizer?.unregister(t); },
865
- async [Symbol.asyncDispose]() { try {
866
- await t.delete();
867
- }
868
- catch { } toDelete?.delete(t.isAt); finalizer?.unregister(t); }
869
- }));
870
- }
871
- export function AutoTempSync(createable_, autoCleanup_) {
872
- let t = createable_.mk(tmp().join(`instrumentality@${cr.randomUUID()}`));
873
- if (autoCleanup_)
874
- registerToCleanup(t);
875
- return Object.freeze(Object.assign(t, {
876
- [Symbol.dispose]() { try {
877
- t.deleteSync();
878
- }
879
- catch { } toDelete?.delete(t.isAt); finalizer?.unregister(t); },
880
- async [Symbol.asyncDispose]() { try {
881
- await t.delete();
882
- }
883
- catch { } toDelete?.delete(t.isAt); finalizer?.unregister(t); }
884
- }));
885
- }
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "url": "https://github.com/clerkburk/instrumentality.git"
6
6
  },
7
7
  "type": "module",
8
- "version": "0.0.8",
8
+ "version": "0.0.9",
9
9
  "main": "./dist/base.js",
10
10
  "types": "./dist/base.d.ts",
11
11
  "devDependencies": {
package/src/road.ts CHANGED
@@ -112,7 +112,7 @@ export abstract class Road {
112
112
  /** The amount of path segments in the absolute path to the file or directory represented by this Road instance, minus one (i.e., the depth of the path in the file system hierarchy). */
113
113
  get depth() { return this.isAt.split(ph.sep).length - 1 }
114
114
  /** Same as {@link isAt} but for compatibility with external APIs. */
115
- toString() { return this.isAt }
115
+ toString(): string { return this.isAt }
116
116
 
117
117
  /**
118
118
  * Creates a new instance of the Road class.
@@ -147,52 +147,32 @@ export abstract class Road {
147
147
  /** @returns An array of {@link Folder} instances representing the ancestors of the current road. */
148
148
  ancestors(): Folder[] { return [...this.ancestorsIt()] }
149
149
 
150
- /**
151
- * Aquires a lock for the path represented by this Road instance, preventing concurrent modifications from this and other Road instances pointing to the same path.
152
- *
153
- * @returns An object with a dispose method that releases the lock when called.
154
- * @throws If the road is immutable, a {@link Err} will be thrown.
155
- *
156
- * @remarks This method MUST be used with a `using` statement to ensure that the lock is released properly. Failing to do so WILL result in deadlocks and other concurrency issues.
157
- * Non-deterministic release is unfortunately not possible due to the nature of JavaScript's garbage collection, thus the lock must be released deterministically by the user (for which the `using` statement is a convenient way to do so).
158
- * @remarks Methods may call other methods that each acquire their own locks, and release them independently, meaning from the perspective of other instances, the lock may appear to be free even if the original method still has work to do.
159
- * To fix this, it's recommeneded to aquire a lock at the beginning and use fs/fp operations within the locked context.
160
- */
161
- protected async lock(): Promise<Disposable & AsyncDisposable> {
150
+ protected reserveLock(allowConcurrent: boolean): Disposable & { previous: Promise<void> | undefined } {
162
151
  if (!this.mutable)
163
152
  throw new Err(`Road to '${this.isAt}' is immutable.`)
164
153
  lockedRoads ??= new Map()
165
154
  const { promise, resolve } = Promise.withResolvers<void>()
166
- const previous = lockedRoads.get(this.isAt)
167
- lockedRoads.set(this.isAt, promise)
168
155
  const isAt = this.isAt
169
- const dispose = () => {
170
- resolve()
171
- if (lockedRoads!.get(isAt) === promise)
172
- lockedRoads!.delete(isAt)
173
- }
174
- await previous
175
- return { [Symbol.dispose]: dispose, [Symbol.asyncDispose]: dispose as any }
176
- }
177
- /**
178
- * Sync version of {@link lock}.
179
- * @throws If the road is currently locked by another operation as it cannot wait for the lock to be released in a synchronous context.
180
- */
181
- protected lockSync(): Disposable & AsyncDisposable {
182
- if (!this.mutable)
183
- throw new Err(`Road to '${this.isAt}' is immutable.`)
184
- lockedRoads ??= new Map()
185
- const { promise, resolve } = Promise.withResolvers<void>()
186
- if (lockedRoads.has(this.isAt))
156
+ const previous = lockedRoads.get(this.isAt)
157
+ if (!allowConcurrent && previous)
187
158
  throw new Err(`Road to '${this.isAt}' is already locked.`)
188
159
  lockedRoads.set(this.isAt, promise)
189
- const isAt = this.isAt
190
- const dispose = () => {
191
- resolve()
192
- if (lockedRoads!.get(isAt) === promise)
193
- lockedRoads!.delete(isAt)
160
+ return {
161
+ [Symbol.dispose]: () => {
162
+ resolve()
163
+ if (lockedRoads!.get(isAt) === promise)
164
+ lockedRoads!.delete(isAt)
165
+ },
166
+ previous,
194
167
  }
195
- return { [Symbol.dispose]: dispose, [Symbol.asyncDispose]: dispose as any }
168
+ }
169
+ async lock(): Promise<Disposable> {
170
+ const l = this.reserveLock(true)
171
+ try { await l.previous } catch {}
172
+ return l
173
+ }
174
+ lockSync(): Disposable {
175
+ return this.reserveLock(false)
196
176
  }
197
177
 
198
178
  /**
@@ -256,14 +236,14 @@ export abstract class Road {
256
236
  using _ = this.lockSync()
257
237
  fs.rmSync(this.isAt, { recursive: true, force: true })
258
238
  }
259
- async copy(into_: Folder, options_?: fs.CopyOptions): Promise<this> {
239
+ async copy(into_: Folder): Promise<this> {
260
240
  const newPath = into_.join(this.name)
261
- await fp.cp(this.isAt, newPath, { recursive: true, ...options_ })
241
+ await fp.cp(this.isAt, newPath, { recursive: true, force: true })
262
242
  return new (this.constructor as new (path: string, typeCheck: boolean) => this)(newPath, false)
263
243
  }
264
- copySync(into_: Folder, options_?: fs.CopySyncOptions): this {
244
+ copySync(into_: Folder): this {
265
245
  const newPath = into_.join(this.name)
266
- fs.cpSync(this.isAt, newPath, { recursive: true, ...options_ })
246
+ fs.cpSync(this.isAt, newPath, { recursive: true, force: true })
267
247
  return new (this.constructor as new (path: string, typeCheck: boolean) => this)(newPath, false)
268
248
  }
269
249
  async move(into_: Folder): Promise<void> {
@@ -291,7 +271,6 @@ export abstract class Road {
291
271
  this.pointsTo = newPath
292
272
  }
293
273
 
294
-
295
274
  // jsdocs for the abstract methods are in the subclasses
296
275
  abstract check(): Promise<boolean>
297
276
  abstract checkSync(): boolean
@@ -333,17 +312,17 @@ export class File extends Road {
333
312
  * @returns A promise that resolves to the newly created `File` instance.
334
313
  * @throws if {@link fp.writeFile} throws.
335
314
  */
336
- static async create(at_: string) {
315
+ static async create(at_: string, data: string | Buffer = "") {
337
316
  try { await fp.access(at_, fsc.W_OK) }
338
- catch { await fp.writeFile(at_, "") }
317
+ catch { await fp.writeFile(at_, data) }
339
318
  return new File(at_, true)
340
319
  }
341
320
  /** Alias for {@link File.create}. */
342
321
  static readonly mk: typeof File.create = File.create
343
322
  /** Synchronous version of {@link File.create}. */
344
- static createSync(at_: string) {
323
+ static createSync(at_: string, data: string | Buffer = "") {
345
324
  try { fs.accessSync(at_, fs.constants.W_OK) }
346
- catch { fs.writeFileSync(at_, "") }
325
+ catch { fs.writeFileSync(at_, data) }
347
326
  return new File(at_, true)
348
327
  }
349
328
  /** Alias for {@link File.createSync}. */
@@ -361,67 +340,25 @@ export class File extends Road {
361
340
  * @throws If the file can't be read due to permission issues or other filesystem errors.
362
341
  */
363
342
  async read(): Promise<Buffer>
364
- async read(encoding_: BufferEncoding, flag_?: string): Promise<string>
365
- async read(encoding_?: BufferEncoding, flag_?: string): Promise<Buffer | string> {
366
- if (encoding_)
367
- return fp.readFile(this.isAt, { encoding: encoding_, flag: flag_ })
368
- else
369
- return fp.readFile(this.isAt)
343
+ async read(options_: Parameters<typeof fp.readFile>[1]): Promise<string>
344
+ async read(options_?: Parameters<typeof fp.readFile>[1]): Promise<Buffer | string> {
345
+ return fp.readFile(this.isAt, options_!)
370
346
  }
371
347
  readSync(): Buffer
372
- readSync(encoding_: BufferEncoding, flag_?: string): string
373
- readSync(encoding_?: BufferEncoding, flag_?: string): Buffer | string {
374
- if (encoding_)
375
- return fs.readFileSync(this.isAt, { encoding: encoding_, flag: flag_ })
376
- else
377
- return fs.readFileSync(this.isAt)
348
+ readSync(options_: Parameters<typeof fs.readFileSync>[1]): string
349
+ readSync(options_?: Parameters<typeof fs.readFileSync>[1]): Buffer | string {
350
+ return fs.readFileSync(this.isAt, options_!)
378
351
  }
379
352
 
380
- async sameAs(other_: File): Promise<boolean> {
381
- if (this.isAt === other_.isAt)
382
- return true
383
- else if ((await fp.lstat(this.isAt)).size !== (await fp.lstat(other_.isAt)).size)
384
- return false
385
- const iter1 = this.itBuff()
386
- const iter2 = other_.itBuff()
387
- while (true) {
388
- const [a, b] = await Promise.all([iter1.next(), iter2.next()])
389
- if (a.done && b.done) return true
390
- if (a.done !== b.done) return false
391
- if (!a.value!.equals(b.value!)) return false
392
- }
393
- }
394
- sameAsSync(other_: File): boolean {
395
- if (this.isAt === other_.isAt)
396
- return true
397
- else if (fs.lstatSync(this.isAt).size !== fs.lstatSync(other_.isAt).size)
398
- return false
399
- const iter1 = this.itBuffSync()
400
- const iter2 = other_.itBuffSync()
401
- while (true) {
402
- const a = iter1.next()
403
- const b = iter2.next()
404
- if (a.done && b.done) return true
405
- if (a.done !== b.done) return false
406
- if (!a.value!.equals(b.value!)) return false
407
- }
408
- }
409
-
410
- async *itBuff(chunkSize_: number = 64 * 1024, flags_: string | number = 'r', mode_?: fs.Mode) {
411
- const fd = await fp.open(this.isAt, flags_, mode_)
353
+ async *itBuff(options_?: fs.ReadStreamOptions): AsyncGenerator<Buffer> {
354
+ const stream = fs.createReadStream(this.isAt, { ...options_, encoding: undefined })
412
355
  try {
413
- const buffer = Buffer.alloc(chunkSize_)
414
- let bytesRead: number
415
- do {
416
- bytesRead = (await fd.read(buffer, 0, chunkSize_, null)).bytesRead
417
- if (bytesRead > 0)
418
- yield Buffer.from(buffer.subarray(0, bytesRead))
419
- } while (bytesRead === chunkSize_)
420
- } finally {
421
- await fd.close()
356
+ for await (const chunk of stream)
357
+ yield chunk
422
358
  }
359
+ finally { if (!stream.destroyed) stream.destroy() }
423
360
  }
424
- *itBuffSync(chunkSize_: number = 64 * 1024, flags_: string | number = 'r', mode_?: fs.Mode) {
361
+ *itBuffSync(chunkSize_: number = 64 * 1024, flags_: string | number = 'r', mode_?: fs.Mode): Generator<Buffer> {
425
362
  const fd = fs.openSync(this.isAt, flags_, mode_)
426
363
  try {
427
364
  const buffer = Buffer.alloc(chunkSize_)
@@ -431,43 +368,47 @@ export class File extends Road {
431
368
  if (bytesRead > 0)
432
369
  yield Buffer.from(buffer.subarray(0, bytesRead))
433
370
  } while (bytesRead === chunkSize_)
434
- } finally {
435
- fs.closeSync(fd)
436
371
  }
372
+ finally { fs.closeSync(fd) }
437
373
  }
438
- async *itLines(chunkSize_: number = 64 * 1024, flags_: string | number = 'r', mode_?: fs.Mode) {
439
- const decoder = new TextDecoder("utf-8", { fatal: true })
440
- let carry = ""
441
-
442
- for await (const chunk of this.itBuff(chunkSize_, flags_, mode_)) {
443
- carry += decoder.decode(chunk, { stream: true })
444
- let newlineINdex: number
445
- while ((newlineINdex = carry.indexOf("\n")) !== -1) {
446
- const line = carry.slice(0, newlineINdex)
447
- yield line.endsWith("\r") ? line.slice(0, -1) : line
448
- carry = carry.slice(newlineINdex + 1)
374
+
375
+ async sameAs(other_: File): Promise<boolean> {
376
+ if (this.isAt === other_.isAt) return true
377
+ const [s1, s2] = await Promise.all([this.size(), other_.size()])
378
+ if (s1 !== s2) return false
379
+ if (s1 === 0) return true
380
+ const iter1 = this.itBuff()
381
+ const iter2 = other_.itBuff()
382
+ try {
383
+ while (true) {
384
+ const [a, b] = await Promise.all([iter1.next(), iter2.next()])
385
+ if (a.done && b.done) return true
386
+ if (a.done !== b.done) return false
387
+ if (!a.value.equals(b.value)) return false
449
388
  }
450
389
  }
451
- carry += decoder.decode()
452
- if (carry.length > 0)
453
- yield carry.endsWith("\r") ? carry.slice(0, -1) : carry
454
- }
455
- *itLinesSync(chunkSize_: number = 64 * 1024, flags_: string | number = 'r', mode_?: fs.Mode) {
456
- const decoder = new TextDecoder("utf-8", { fatal: true })
457
- let carry = ""
458
-
459
- for (const chunk of this.itBuffSync(chunkSize_, flags_, mode_)) {
460
- carry += decoder.decode(chunk, { stream: true })
461
- let newlineINdex: number
462
- while ((newlineINdex = carry.indexOf("\n")) !== -1) {
463
- const line = carry.slice(0, newlineINdex)
464
- yield line.endsWith("\r") ? line.slice(0, -1) : line
465
- carry = carry.slice(newlineINdex + 1)
390
+ finally { await Promise.all([iter1.return?.(undefined), iter2.return?.(undefined)]) }
391
+ }
392
+ sameAsSync(other_: File): boolean {
393
+ if (this.isAt === other_.isAt) return true
394
+ const [s1, s2] = [this.sizeSync(), other_.sizeSync()]
395
+ if (s1 !== s2) return false
396
+ if (s1 === 0) return true
397
+ const iter1 = this.itBuffSync()
398
+ const iter2 = other_.itBuffSync()
399
+ try {
400
+ while (true) {
401
+ const a = iter1.next()
402
+ const b = iter2.next()
403
+ if (a.done && b.done) return true
404
+ if (a.done !== b.done) return false
405
+ if (!a.value!.equals(b.value!)) return false
466
406
  }
467
407
  }
468
- carry += decoder.decode()
469
- if (carry.length > 0)
470
- yield carry.endsWith("\r") ? carry.slice(0, -1) : carry
408
+ finally {
409
+ try { iter1.return?.(undefined) } catch {}
410
+ try { iter2.return?.(undefined) } catch {}
411
+ }
471
412
  }
472
413
 
473
414
  async hash(algorithm_?: string, options_?: cr.HashOptions): Promise<Buffer>
@@ -492,17 +433,19 @@ export class File extends Road {
492
433
 
493
434
  async writeAtomic(data_: Buffer | string, options_?: fs.WriteFileOptions) {
494
435
  using _ = await this.lock()
495
- const temp = await Temp(File) // Don't use `using` as we won't clean it up
496
- await fp.rename(temp.isAt, this.parent().join(temp.name)) // Move temp file to the same directory as the target
497
- await fp.writeFile(temp.isAt, data_, options_) // Write data to the temp file
498
- await fp.rename(temp.isAt, this.isAt) // Replace the target file with the temp file atomically
436
+ await this.parent().borrow(File, async tmp => {
437
+ using _ = await tmp.lock()
438
+ await fp.writeFile(tmp.isAt, data_, options_)
439
+ await fp.rename(tmp.isAt, this.isAt)
440
+ })
499
441
  }
500
442
  writeAtomicSync(data_: Buffer | string, options_?: fs.WriteFileOptions) {
501
443
  using _ = this.lockSync()
502
- const temp = TempSync(File) // Don't use `using` as we won't clean it up
503
- fs.renameSync(temp.isAt, this.parent().join(temp.name)) // Move temp file to the same directory as the target
504
- fs.writeFileSync(temp.isAt, data_, options_) // Write data to the temp file
505
- fs.renameSync(temp.isAt, this.isAt) // Replace the target file with the temp file atomically
444
+ this.parent().borrowSync(File, tmp => {
445
+ using _ = tmp.lockSync()
446
+ fs.writeFileSync(tmp.isAt, data_, options_)
447
+ fs.renameSync(tmp.isAt, this.isAt)
448
+ })
506
449
  }
507
450
 
508
451
  async write(data_: Buffer | string, options_?: fs.WriteFileOptions) {
@@ -574,18 +517,13 @@ export class Folder extends Road {
574
517
  async list<T extends Road>(filter_: filter_t<T>): Promise<T[]>
575
518
  async list<T extends Road>(filter_?: filter_t<T>): Promise<Road[] | T[]> {
576
519
  const entries = (await fp.readdir(this.isAt, { withFileTypes: true })).map(e => new (resolveDirent(e))(this.join(e.name), false))
577
- const resolvedEntries = await Promise.all(entries)
578
- if (!filter_)
579
- return resolvedEntries
580
- return resolvedEntries.filter(entry => filter_(entry))
520
+ return filter_ ? entries.filter(entry => filter_(entry)) : entries
581
521
  }
582
522
  listSync(): Road[]
583
523
  listSync<T extends Road>(filter_: filter_t<T>): T[]
584
524
  listSync<T extends Road>(filter_?: filter_t<T>): Road[] | T[] {
585
525
  const entries = fs.readdirSync(this.isAt, { withFileTypes: true }).map(e => new (resolveDirent(e))(this.join(e.name), false))
586
- if (!filter_)
587
- return entries
588
- return entries.filter(entry => filter_(entry))
526
+ return filter_ ? entries.filter(entry => filter_(entry)) : entries
589
527
  }
590
528
 
591
529
  walk(): AsyncIterable<Road>
@@ -623,9 +561,8 @@ export class Folder extends Road {
623
561
  if (found instanceof expect_)
624
562
  return found as T
625
563
  return null
626
- } catch {
627
- return null
628
564
  }
565
+ catch { return null }
629
566
  }
630
567
  findSync(name_: string): Road | null
631
568
  findSync<T extends Road>(name_: string, expect_: road_t<T>): T | null
@@ -637,22 +574,32 @@ export class Folder extends Road {
637
574
  if (found instanceof expect_)
638
575
  return found as T
639
576
  return null
640
- } catch(e: unknown) {
641
- return null
642
577
  }
578
+ catch(e: unknown) { return null }
643
579
  }
644
580
 
645
- async add<T extends Road>(name_: string, createable_: { create: (at: string) => Promise<T> }): Promise<T> {
581
+ async add<T extends Road>(name_: string, createable_: { mk: (at: string) => Promise<T> }): Promise<T> {
646
582
  const newPath = this.join(name_)
647
- await createable_.create(newPath)
583
+ await createable_.mk(newPath)
648
584
  return (await factory(newPath)) as unknown as T
649
585
  }
650
- addSync<T extends Road>(name_: string, createable_: { createSync: (at: string) => T }): T {
586
+ addSync<T extends Road>(name_: string, createable_: { mkSync: (at: string) => T }): T {
651
587
  const newPath = this.join(name_)
652
- createable_.createSync(newPath)
588
+ createable_.mkSync(newPath)
653
589
  return factorySync(newPath) as unknown as T
654
590
  }
655
591
 
592
+ async borrow<T extends Road>(createable_: { mk: (at: string) => Promise<T> }, cb_: (r: T) => Promise<void> | void): Promise<void> {
593
+ const path = this.join(`instrumentality@${crypto.randomUUID()}`)
594
+ try { await cb_(await createable_.mk(path)) }
595
+ finally { await fp.rm(path, { recursive: true, force: true }) }
596
+ }
597
+ borrowSync<T extends Road>(createable_: { mkSync: (at: string) => T }, cb_: (r: T) => void): void {
598
+ const path = this.join(`instrumentality@${crypto.randomUUID()}`)
599
+ try { cb_(createable_.mkSync(path)) }
600
+ finally { fs.rmSync(path, { recursive: true, force: true }) }
601
+ }
602
+
656
603
  async size(): Promise<number> {
657
604
  let size = 0
658
605
  for await (const entry of this.it())
@@ -733,7 +680,6 @@ export class SymbolicLink extends Road {
733
680
  override isSymbolicLink(): this is SymbolicLink { return true as const }
734
681
  }
735
682
  export { SymbolicLink as Symlink }
736
- here().walk(r => !r.isSymlink())
737
683
 
738
684
 
739
685
 
@@ -784,68 +730,4 @@ export class Socket extends UnusableRoad {
784
730
  async check(): Promise<boolean> { try { return (await fp.lstat(this.isAt)).isSocket() } catch { return false } }
785
731
  checkSync(): boolean { try { return fs.lstatSync(this.isAt).isSocket() } catch { return false } }
786
732
  override isSocket(): this is Socket { return true as const }
787
- }
788
-
789
-
790
-
791
- export async function Temp<T extends Road>(createable_: { create: (at: string) => Promise<T> }): Promise<T & Disposable & AsyncDisposable> {
792
- let t = await createable_.create(tmp().join(`instrumentality@${cr.randomUUID()}`))
793
- return Object.assign(t, {
794
- [Symbol.dispose]() { try { t.deleteSync() } catch {} toDelete?.delete(t.isAt); finalizer?.unregister(t) },
795
- async [Symbol.asyncDispose]() { try { await t.delete() } catch {} toDelete?.delete(t.isAt); finalizer?.unregister(t) }
796
- })
797
- }
798
- export function TempSync<T extends Road>(createable_: { createSync: (at: string) => T }): T & Disposable & AsyncDisposable {
799
- let t = createable_.createSync(tmp().join(`instrumentality@${cr.randomUUID()}`))
800
- return Object.assign(t, {
801
- [Symbol.dispose]() { try { t.deleteSync() } catch {} toDelete?.delete(t.isAt); finalizer?.unregister(t) },
802
- async [Symbol.asyncDispose]() { try { await t.delete() } catch {} toDelete?.delete(t.isAt); finalizer?.unregister(t) }
803
- })
804
- }
805
-
806
-
807
- let finalizer: FinalizationRegistry<string> | null = null
808
- let toDelete: Set<string> | null = null
809
- let exitHandlerRegistered: boolean | null = null
810
- /**
811
- * Forcefully cleans up all files and folders registered for cleanup on exit.
812
- */
813
- function forceCleanupToDelete() {
814
- for (const path of toDelete ?? [])
815
- try { fs.rmSync(path, { force: true, recursive: true }) } catch {}
816
- toDelete?.clear()
817
- toDelete = null
818
- finalizer = null
819
- if (exitHandlerRegistered)
820
- process.off('exit', forceCleanupToDelete)
821
- exitHandlerRegistered = false
822
- }
823
- export function registerToCleanup(self_: Road) {
824
- finalizer ??= new FinalizationRegistry<string>(p => { try { fs.rmSync(p, { force: true, recursive: true }) } catch {}; toDelete?.delete(p) })
825
- toDelete ??= new Set()
826
- if (!exitHandlerRegistered) {
827
- process.once('exit', forceCleanupToDelete)
828
- exitHandlerRegistered = true
829
- }
830
- toDelete.add(self_.isAt)
831
- finalizer.register(self_, self_.isAt, self_)
832
- }
833
-
834
-
835
- export async function AutoTemp<T extends Road>(createable_: { mk: (at: string) => Promise<T> }): Promise<T & Disposable & AsyncDisposable> {
836
- let t = await createable_.mk(tmp().join(`instrumentality@${cr.randomUUID()}`))
837
- registerToCleanup(t)
838
- return Object.freeze(Object.assign(t, {
839
- [Symbol.dispose]() { try { t.deleteSync() } catch {} toDelete?.delete(t.isAt); finalizer?.unregister(t) },
840
- async [Symbol.asyncDispose]() { try { await t.delete() } catch {} toDelete?.delete(t.isAt); finalizer?.unregister(t) }
841
- }))
842
- }
843
- export function AutoTempSync<T extends Road>(createable_: { mk: (at: string) => T }, autoCleanup_: boolean): T & Disposable & AsyncDisposable {
844
- let t = createable_.mk(tmp().join(`instrumentality@${cr.randomUUID()}`))
845
- if (autoCleanup_)
846
- registerToCleanup(t)
847
- return Object.freeze(Object.assign(t, {
848
- [Symbol.dispose]() { try { t.deleteSync() } catch {} toDelete?.delete(t.isAt); finalizer?.unregister(t) },
849
- async [Symbol.asyncDispose]() { try { await t.delete() } catch {} toDelete?.delete(t.isAt); finalizer?.unregister(t) }
850
- }))
851
733
  }