instrumentality 0.0.13 → 0.0.15

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/src/road.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import * as cr from "node:crypto"
2
3
  import * as fs from "node:fs"; import { constants as fsc } from "node:fs"
3
4
  import * as fp from "node:fs/promises"
@@ -57,25 +58,6 @@ export { resolveDirent as resDirent }
57
58
 
58
59
 
59
60
 
60
- /**
61
- * Creates the appropriate subclass of {@link Road} based on the file mode of the specified path.
62
- *
63
- * @param path_ The path to follow.
64
- * @returns A new instance of {@link Road}.
65
- * @throws If {@link fp.lstat}/{@link fs.lstatSync} fails to retrieved the status of {@link path_}.
66
- */
67
- export async function factory(path_: string) {
68
- return new (resolveStat((await fp.lstat(path_)).mode))(path_, false)
69
- }
70
- export { factory as fac, factory as mk }
71
- /** Sync version of {@link factory}. */
72
- export function factorySync(path_: string) {
73
- return new (resolveStat(fs.lstatSync(path_).mode))(path_, false)
74
- }
75
- export { factorySync as facSync, factorySync as mkSync }
76
-
77
-
78
-
79
61
  /**
80
62
  * A map that keeps track of locked roads to prevent concurrent modifications.
81
63
  *
@@ -97,19 +79,28 @@ export let lockedRoads: Map<string, Promise<void>> | null = null
97
79
  * It is more like a memory representation, similar to a pointer in low-level programming languages; other processes might mess with the underlying entry. There are methods to check for consistency, but they are not guaranteed to be foolproof.
98
80
  */
99
81
  export abstract class Road {
100
- /** The absolute path to the file or directory that this Road instance represents.
82
+ /** The absolute path to the entry that this Road instance represents.
101
83
  * @remarks Intentionally made protected to prevent external modification, as changing this value could lead to inconsistencies and unexpected behavior. */
102
84
  protected pointsTo: string
103
- /** Indicates whether the file or directory represented by this Road instance can be modified.
85
+ /** Indicates which operations are allowed on the entry represented by this Road instance.
104
86
  * Changing this value does not affect the actual file system permissions, but rather serves as a safeguard within the application to prevent accidental modifications. */
105
- mutable: boolean = true
87
+ writable = true
88
+ moveable = true
89
+ deletable = true
90
+ copyable = true
91
+ renameable = true
92
+ assertWrite() { if (!this.writable) throw new Err(`Road to '${this.isAt}' isn't writable.`) }
93
+ assertMove() { if (!this.moveable) throw new Err(`Road to '${this.isAt}' isn't moveable.`) }
94
+ assertDelete() { if (!this.deletable) throw new Err(`Road to '${this.isAt}' isn't deletable.`) }
95
+ assertCopy() { if (!this.copyable) throw new Err(`Road to '${this.isAt}' isn't copyable.`) }
96
+ assertRename() { if (!this.renameable) throw new Err(`Road to '${this.isAt}' isn't renameable.`) }
106
97
 
107
98
  // Quick accessors
108
99
  /** Copy of the absolute path. */
109
100
  get isAt() { return this.pointsTo }
110
101
  /** Name of the road without the path (including extensions). */
111
102
  get name() { return this.isAt.slice(this.isAt.lastIndexOf(ph.sep) + 1) }
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). */
103
+ /** The amount of path segments in the absolute path to the entry represented by this Road instance, minus one (i.e., the depth of the path in the file system hierarchy). */
113
104
  get depth() { return this.isAt.split(ph.sep).length - 1 }
114
105
  /** Same as {@link isAt} but for compatibility with external APIs. */
115
106
  toString(): string { return this.isAt }
@@ -124,7 +115,7 @@ export abstract class Road {
124
115
  */
125
116
  constructor(path_: string, typeCheck_: boolean) {
126
117
  this.pointsTo = ph.resolve(path_)
127
- if (typeCheck_ && !this.checkSync())
118
+ if (typeCheck_ && !this.checkSync(true))
128
119
  throw new Err(`Type mismatch: '${this.isAt}'`)
129
120
  }
130
121
 
@@ -148,8 +139,6 @@ export abstract class Road {
148
139
  ancestors(): Folder[] { return [...this.ancestorsIt()] }
149
140
 
150
141
  protected reserveLock(allowConcurrent: boolean): Disposable & { previous: Promise<void> | undefined } {
151
- if (!this.mutable)
152
- throw new Err(`Road to '${this.isAt}' is immutable.`)
153
142
  lockedRoads ??= new Map()
154
143
  const { promise, resolve } = Promise.withResolvers<void>()
155
144
  const isAt = this.isAt
@@ -168,7 +157,7 @@ export abstract class Road {
168
157
  }
169
158
  async lock(): Promise<Disposable> {
170
159
  const l = this.reserveLock(true)
171
- try { await l.previous } catch {}
160
+ try { await l.previous } catch { null }
172
161
  return l
173
162
  }
174
163
  lockSync(): Disposable {
@@ -188,7 +177,7 @@ export abstract class Road {
188
177
  async untilAccessible(abs: AbortSignal, expectMode = fsc.F_OK, cb_?: (err: unknown) => unknown): Promise<void> {
189
178
  const watcher = fs.watch(this.isAt)
190
179
  try {
191
- for await (let _ of on(watcher, 'change', { signal: abs })) {
180
+ for await (const _ of on(watcher, 'change', { signal: abs })) {
192
181
  try {
193
182
  await fp.access(this.isAt, expectMode)
194
183
  return
@@ -209,7 +198,7 @@ export abstract class Road {
209
198
  async onChange<T>(abs_: AbortSignal, cb_?: () => T) {
210
199
  const watcher = fs.watch(this.isAt)
211
200
  try {
212
- for await (let _ of on(watcher, 'change', { signal: abs_ }))
201
+ for await (const _ of on(watcher, 'change', { signal: abs_ }))
213
202
  return await cb_?.() ?? null
214
203
  return null
215
204
  }
@@ -228,43 +217,51 @@ export abstract class Road {
228
217
 
229
218
  /** Wrapper around {@link fp.rm} with locking. */
230
219
  async delete(): Promise<void> {
220
+ this.assertDelete()
231
221
  using _ = await this.lock()
232
222
  await fp.rm(this.isAt, { recursive: true, force: true })
233
223
  }
234
224
  /** Wrapper around {@link fs.rmSync} with locking. */
235
225
  deleteSync(): void {
226
+ this.assertDelete()
236
227
  using _ = this.lockSync()
237
228
  fs.rmSync(this.isAt, { recursive: true, force: true })
238
229
  }
239
230
  async copy(into_: Folder): Promise<this> {
231
+ this.assertCopy()
240
232
  const newPath = into_.join(this.name)
241
233
  await fp.cp(this.isAt, newPath, { recursive: true, force: true })
242
234
  return new (this.constructor as new (path: string, typeCheck: boolean) => this)(newPath, false)
243
235
  }
244
236
  copySync(into_: Folder): this {
237
+ this.assertCopy()
245
238
  const newPath = into_.join(this.name)
246
239
  fs.cpSync(this.isAt, newPath, { recursive: true, force: true })
247
240
  return new (this.constructor as new (path: string, typeCheck: boolean) => this)(newPath, false)
248
241
  }
249
242
  async move(into_: Folder): Promise<void> {
243
+ this.assertMove()
250
244
  using _ = await this.lock()
251
245
  const newPath = into_.join(this.name)
252
246
  await fp.rename(this.isAt, newPath)
253
247
  this.pointsTo = newPath
254
248
  }
255
249
  moveSync(into_: Folder): void {
250
+ this.assertMove()
256
251
  using _ = this.lockSync()
257
252
  const newPath = into_.join(this.name)
258
253
  fs.renameSync(this.isAt, newPath)
259
254
  this.pointsTo = newPath
260
255
  }
261
256
  async rename(newName_: string): Promise<void> {
257
+ this.assertRename()
262
258
  using _ = await this.lock()
263
259
  const newPath = this.parent().join(newName_)
264
260
  await fp.rename(this.isAt, newPath)
265
261
  this.pointsTo = newPath
266
262
  }
267
263
  renameSync(newName_: string): void {
264
+ this.assertRename()
268
265
  using _ = this.lockSync()
269
266
  const newPath = this.parent().join(newName_)
270
267
  fs.renameSync(this.isAt, newPath)
@@ -272,8 +269,8 @@ export abstract class Road {
272
269
  }
273
270
 
274
271
  // jsdocs for the abstract methods are in the subclasses
275
- abstract check(): Promise<boolean>
276
- abstract checkSync(): boolean
272
+ abstract check(throwOnError_: boolean): Promise<boolean>
273
+ abstract checkSync(throwOnError_: boolean): boolean
277
274
 
278
275
  /** Type narrowing for {@link File} (similar to `instanceof` without unnecessary runtime checks). */
279
276
  isFile(): this is File { return false as const }
@@ -298,9 +295,30 @@ export abstract class Road {
298
295
  /** Type narrowing for {@link Socket} (similar to `instanceof` without unnecessary runtime checks). */
299
296
  isSocket(): this is Socket { return false as const }
300
297
  }
298
+
299
+
300
+
301
301
  /** Constructor type for a subclass of {@link Road}. */
302
302
  export type road_t<T extends Road> = new (...args_: ConstructorParameters<typeof Road>) => T
303
303
 
304
+
305
+
306
+
307
+
308
+ /**
309
+ * Creates the appropriate subclass of {@link Road} based on the file mode of the specified path.
310
+ *
311
+ * @param path_ The path to follow.
312
+ * @returns A new instance of {@link Road}.
313
+ * @throws If {@link fp.lstat}/{@link fs.lstatSync} fails to retrieved the status of {@link path_}.
314
+ */
315
+ export async function road(path_: string) { return new (resolveStat((await fp.lstat(path_)).mode))(path_, false) }
316
+ export { road as fac, road as mk, road as factory }
317
+ /** Sync version of {@link road}. */
318
+ export function roadSync(path_: string) { return new (resolveStat((fs.lstatSync(path_).mode)))(path_, false) }
319
+ export { roadSync as facSync, roadSync as mkSync, roadSync as factorySync }
320
+
321
+
304
322
 
305
323
 
306
324
  /** Subclass of {@link Road} that represents a file. */
@@ -342,7 +360,7 @@ export class File extends Road {
342
360
  async read(): Promise<Buffer>
343
361
  async read(options_: Parameters<typeof fp.readFile>[1]): Promise<string>
344
362
  async read(options_?: Parameters<typeof fp.readFile>[1]): Promise<Buffer | string> {
345
- return fp.readFile(this.isAt, options_!)
363
+ return await fp.readFile(this.isAt, options_!)
346
364
  }
347
365
  readSync(): Buffer
348
366
  readSync(options_: Parameters<typeof fs.readFileSync>[1]): string
@@ -406,8 +424,8 @@ export class File extends Road {
406
424
  }
407
425
  }
408
426
  finally {
409
- try { iter1.return?.(undefined) } catch {}
410
- try { iter2.return?.(undefined) } catch {}
427
+ try { iter1.return?.(undefined) } catch { null }
428
+ try { iter2.return?.(undefined) } catch { null }
411
429
  }
412
430
  }
413
431
 
@@ -432,16 +450,20 @@ export class File extends Road {
432
450
  sizeSync(): number { return this.lstatSync().size }
433
451
 
434
452
  async writeAtomic(data_: Buffer | string, options_?: fs.WriteFileOptions) {
453
+ this.assertWrite()
435
454
  using _ = await this.lock()
436
455
  await this.parent().borrow(File, async tmp => {
456
+ tmp.assertWrite()
437
457
  using _ = await tmp.lock()
438
458
  await fp.writeFile(tmp.isAt, data_, options_)
439
459
  await fp.rename(tmp.isAt, this.isAt)
440
460
  })
441
461
  }
442
462
  writeAtomicSync(data_: Buffer | string, options_?: fs.WriteFileOptions) {
463
+ this.assertWrite()
443
464
  using _ = this.lockSync()
444
465
  this.parent().borrowSync(File, tmp => {
466
+ tmp.assertWrite()
445
467
  using _ = tmp.lockSync()
446
468
  fs.writeFileSync(tmp.isAt, data_, options_)
447
469
  fs.renameSync(tmp.isAt, this.isAt)
@@ -449,14 +471,17 @@ export class File extends Road {
449
471
  }
450
472
 
451
473
  async write(data_: Buffer | string, options_?: fs.WriteFileOptions) {
474
+ this.assertWrite()
452
475
  using _ = await this.lock()
453
476
  await fp.writeFile(this.isAt, data_, options_)
454
477
  }
455
478
  writeSync(data_: Buffer | string, options_?: fs.WriteFileOptions) {
479
+ this.assertWrite()
456
480
  using _ = this.lockSync()
457
481
  fs.writeFileSync(this.isAt, data_, options_)
458
482
  }
459
483
  async writePast(offset_: number, data_: Buffer | string) {
484
+ this.assertWrite()
460
485
  using _ = await this.lock()
461
486
  const fd = await fp.open(this.isAt, 'r+')
462
487
  try {
@@ -465,6 +490,7 @@ export class File extends Road {
465
490
  } finally { await fd.close() }
466
491
  }
467
492
  writePastSync(offset_: number, data_: Buffer | string) {
493
+ this.assertWrite()
468
494
  using _ = this.lockSync()
469
495
  const fd = fs.openSync(this.isAt, 'r+')
470
496
  try {
@@ -473,6 +499,7 @@ export class File extends Road {
473
499
  } finally { fs.closeSync(fd) }
474
500
  }
475
501
  async truncWritePast(offset_: number, data_: Buffer | string) {
502
+ this.assertWrite()
476
503
  using _ = await this.lock()
477
504
  const fd = await fp.open(this.isAt, 'r+')
478
505
  try {
@@ -483,6 +510,7 @@ export class File extends Road {
483
510
  finally { await fd.close() }
484
511
  }
485
512
  truncWritePastSync(offset_: number, data_: Buffer | string) {
513
+ this.assertWrite()
486
514
  using _ = this.lockSync()
487
515
  const fd = fs.openSync(this.isAt, 'r+')
488
516
  try {
@@ -493,16 +521,18 @@ export class File extends Road {
493
521
  finally { fs.closeSync(fd) }
494
522
  }
495
523
  async append(data_: Buffer | string, options_?: fs.WriteFileOptions) {
524
+ this.assertWrite()
496
525
  using _ = await this.lock()
497
526
  await fp.appendFile(this.isAt, data_, options_)
498
527
  }
499
528
  appendSync(data_: Buffer | string, options_?: fs.WriteFileOptions) {
529
+ this.assertWrite()
500
530
  using _ = this.lockSync()
501
531
  fs.appendFileSync(this.isAt, data_, options_)
502
532
  }
503
533
 
504
- async check(): Promise<boolean> { try { return (await fp.lstat(this.isAt)).isFile() } catch { return false } }
505
- checkSync(): boolean { try { return fs.lstatSync(this.isAt).isFile() } catch { return false } }
534
+ async check(throwOnError_: boolean): Promise<boolean> { try { return (await fp.lstat(this.isAt)).isFile() } catch (e) { if (throwOnError_) throw e; return false } }
535
+ checkSync(throwOnError_: boolean): boolean { try { return fs.lstatSync(this.isAt).isFile() } catch (e) { if (throwOnError_) throw e; return false } }
506
536
 
507
537
  override isFile(): this is File { return true as const }
508
538
  }
@@ -513,7 +543,8 @@ export function file(...args: ConstructorParameters<typeof File>): File { return
513
543
 
514
544
 
515
545
  /** Helper type for filtering {@link Road} instances. */
516
- export type filter_t<T extends Road> = ((road: Road) => road is T)
546
+ export type filter_t<T extends Road> = ((found: Road) => found is T)
547
+
517
548
 
518
549
  export class Folder extends Road {
519
550
  static async create(at_: string) {
@@ -591,52 +622,48 @@ export class Folder extends Road {
591
622
  }
592
623
 
593
624
  async find(name_: string): Promise<Road | null>
594
- async find<T extends Road>(name_: string, expect_: road_t<T>): Promise<T | null>
595
- async find<T extends Road>(name_: string, expect_?: road_t<T>): Promise<Road | T | null> {
625
+ async find<T extends Road>(name_: string, filter_: filter_t<T>): Promise<T | null>
626
+ async find<T extends Road>(name_: string, filter_?: filter_t<T>): Promise<Road | T | null> {
596
627
  try {
597
- const found = await factory(this.join(name_))
598
- if (!expect_)
628
+ const found = await road(this.join(name_))
629
+ if (!filter_ || filter_(found))
599
630
  return found
600
- if (found instanceof expect_)
601
- return found as T
602
631
  return null
603
- }
604
- catch { return null }
632
+ } catch { return null }
605
633
  }
606
634
  findSync(name_: string): Road | null
607
- findSync<T extends Road>(name_: string, expect_: road_t<T>): T | null
608
- findSync<T extends Road>(name_: string, expect_?: road_t<T>): Road | T | null {
635
+ findSync<T extends Road>(name_: string, filter_: filter_t<T>): T | null
636
+ findSync<T extends Road>(name_: string, filter_?: filter_t<T>): Road | T | null {
609
637
  try {
610
- const found = factorySync(this.join(name_))
611
- if (!expect_)
638
+ const found = roadSync(this.join(name_))
639
+ if (!filter_ || filter_(found))
612
640
  return found
613
- if (found instanceof expect_)
614
- return found as T
615
641
  return null
616
- }
617
- catch(e: unknown) { return null }
642
+ } catch { return null }
618
643
  }
619
644
 
620
645
  async add<T extends Road>(name_: string, createable_: { mk: (at: string) => Promise<T> }): Promise<T> {
646
+ this.assertWrite()
621
647
  const newPath = this.join(name_)
622
648
  await createable_.mk(newPath)
623
- return (await factory(newPath)) as unknown as T
649
+ return (await road(newPath)) as unknown as T
624
650
  }
625
651
  addSync<T extends Road>(name_: string, createable_: { mkSync: (at: string) => T }): T {
652
+ this.assertWrite()
626
653
  const newPath = this.join(name_)
627
654
  createable_.mkSync(newPath)
628
- return factorySync(newPath) as unknown as T
655
+ return roadSync(newPath) as unknown as T
629
656
  }
630
657
 
631
658
  async borrow<T extends Road>(createable_: { mk: (at: string) => Promise<T> }, cb_: (r: T) => Promise<void> | void): Promise<void> {
632
- const path = this.join(`instrumentality@${crypto.randomUUID()}`)
633
- try { await cb_(await createable_.mk(path)) }
634
- finally { await fp.rm(path, { recursive: true, force: true }) }
659
+ const created = await createable_.mk(this.join(`instrumentality@${crypto.randomUUID()}`))
660
+ try { await cb_(created) }
661
+ finally { await fp.rm(created.isAt, { recursive: true, force: true }) }
635
662
  }
636
663
  borrowSync<T extends Road>(createable_: { mkSync: (at: string) => T }, cb_: (r: T) => void): void {
637
- const path = this.join(`instrumentality@${crypto.randomUUID()}`)
638
- try { cb_(createable_.mkSync(path)) }
639
- finally { fs.rmSync(path, { recursive: true, force: true }) }
664
+ const created = createable_.mkSync(this.join(`instrumentality@${crypto.randomUUID()}`))
665
+ try { cb_(created) }
666
+ finally { fs.rmSync(created.isAt, { recursive: true, force: true }) }
640
667
  }
641
668
 
642
669
  async size(): Promise<number> {
@@ -652,8 +679,8 @@ export class Folder extends Road {
652
679
  return size
653
680
  }
654
681
 
655
- async check(): Promise<boolean> { try { return (await fp.lstat(this.isAt)).isDirectory() } catch { return false } }
656
- checkSync(): boolean { try { return fs.lstatSync(this.isAt).isDirectory() } catch { return false } }
682
+ async check(throwOnError_: boolean): Promise<boolean> { try { return (await fp.lstat(this.isAt)).isDirectory() } catch (e) { if (throwOnError_) throw e; return false } }
683
+ checkSync(throwOnError_: boolean): boolean { try { return fs.lstatSync(this.isAt).isDirectory() } catch (e) { if (throwOnError_) throw e; return false } }
657
684
 
658
685
  override isFolder(): this is Folder { return true as const }
659
686
  override isDir(): this is Folder { return true as const }
@@ -663,13 +690,14 @@ export class Folder extends Road {
663
690
 
664
691
  export function folder(...args: ConstructorParameters<typeof Folder>): Folder { return new Folder(...args) }
665
692
  export function dir(...args: ConstructorParameters<typeof Folder>): Folder { return new Folder(...args) }
693
+ export function directory(...args: ConstructorParameters<typeof Folder>): Folder { return new Folder(...args) }
666
694
 
667
695
 
668
696
  export function sysRoot() { return new Folder(ph.parse(process.cwd()).root, false) }
669
697
  export function home() { return new Folder(os.homedir(), false) }
670
698
  export function tmp() { return new Folder(os.tmpdir(), false) }
671
699
  export function here() { return new Folder(process.cwd(), false) }
672
- export { Folder as Dir, Folder as Directory, Folder as Dict, Folder as Dictionary }
700
+ export { Folder as Dir, Folder as Directory }
673
701
 
674
702
 
675
703
 
@@ -688,17 +716,21 @@ export class SymbolicLink extends Road {
688
716
  static readonly mkSync: typeof SymbolicLink.createSync = SymbolicLink.createSync
689
717
 
690
718
  async target() {
691
- return factory(ph.resolve(ph.dirname(this.isAt), await fp.readlink(this.isAt)))
719
+ return await road(ph.resolve(ph.dirname(this.isAt), await fp.readlink(this.isAt)))
692
720
  }
693
721
  targetSync() {
694
- return factorySync(ph.resolve(ph.dirname(this.isAt), fs.readlinkSync(this.isAt)))
722
+ return roadSync(ph.resolve(ph.dirname(this.isAt), fs.readlinkSync(this.isAt)))
695
723
  }
696
724
  async retarget(to_: Road) {
725
+ this.assertDelete()
726
+ this.assertWrite()
697
727
  using _ = await this.lock()
698
728
  await fp.unlink(this.isAt)
699
729
  await fp.symlink(to_.isAt, this.isAt)
700
730
  }
701
731
  retargetSync(to_: Road) {
732
+ this.assertDelete()
733
+ this.assertWrite()
702
734
  using _ = this.lockSync()
703
735
  fs.unlinkSync(this.isAt)
704
736
  fs.symlinkSync(to_.isAt, this.isAt)
@@ -708,16 +740,18 @@ export class SymbolicLink extends Road {
708
740
  sizeSync(): number { return this.lstatSync().size }
709
741
 
710
742
  override async delete() {
743
+ this.assertDelete()
711
744
  using _ = await this.lock()
712
745
  await fp.unlink(this.isAt)
713
746
  }
714
747
  override deleteSync() {
748
+ this.assertDelete()
715
749
  using _ = this.lockSync()
716
750
  fs.unlinkSync(this.isAt)
717
751
  }
718
752
 
719
- async check(): Promise<boolean> { try { return (await fp.lstat(this.isAt)).isSymbolicLink() } catch { return false } }
720
- checkSync(): boolean { try { return fs.lstatSync(this.isAt).isSymbolicLink() } catch { return false } }
753
+ async check(throwOnError_: boolean): Promise<boolean> { try { return (await fp.lstat(this.isAt)).isSymbolicLink() } catch (e) { if (throwOnError_) throw e; return false } }
754
+ checkSync(throwOnError_: boolean): boolean { try { return fs.lstatSync(this.isAt).isSymbolicLink() } catch (e) { if (throwOnError_) throw e; return false } }
721
755
 
722
756
  override isSymlink(): this is SymbolicLink { return true as const }
723
757
  override isSymbolicLink(): this is SymbolicLink { return true as const }
@@ -731,55 +765,64 @@ export function symlink(...args: ConstructorParameters<typeof SymbolicLink>): Sy
731
765
 
732
766
 
733
767
 
768
+ /**
769
+ * Represents a system-level resource that is not subject to modification.
770
+ * All modification operations will throw an error.
771
+ *
772
+ * One could say 'this road truly is *unusable*.' hehe
773
+ */
734
774
  export abstract class UnusableRoad extends Road {
735
- override readonly mutable = false as const // Modification will cause system issues (e.g. deleting a device file)
736
- async size(): Promise<0> { return 0 }
775
+ // Modification will cause system issues (e.g. deleting a device file)
776
+ override readonly writable = false as never
777
+ override readonly moveable = false as never
778
+ override readonly deletable = false as never
779
+ override readonly copyable = false as never
780
+ size(): Promise<0> { return Promise.resolve(0) }
737
781
  sizeSync(): 0 { return 0 }
738
782
  error(): never { throw new Err(`${this.constructor.name} at '${this.isAt}' is a system-level resource thus not subject to modification.`) }
739
- /** @deprecated System-level resources (UnusableRoad) can't/shouldn't be locked */
783
+ /** @deprecated System-level resources ({@link UnusableRoad}) can't/shouldn't be locked */
740
784
  override lock(): never { return this.error() }
741
- /** @deprecated System-level resources (UnusableRoad) can't/shouldn't be locked */
785
+ /** @deprecated System-level resources ({@link UnusableRoad}) can't/shouldn't be locked */
742
786
  override lockSync(): never { return this.error() }
743
- /** @deprecated System-level resources (UnusableRoad) can't/shouldn't be deleted */
787
+ /** @deprecated System-level resources ({@link UnusableRoad}) can't/shouldn't be deleted */
744
788
  override delete(): never { return this.error() }
745
- /** @deprecated System-level resources (UnusableRoad) can't/shouldn't be deleted */
789
+ /** @deprecated System-level resources ({@link UnusableRoad}) can't/shouldn't be deleted */
746
790
  override deleteSync(): never { return this.error() }
747
- /** @deprecated System-level resources (UnusableRoad) can't/shouldn't be moved */
791
+ /** @deprecated System-level resources ({@link UnusableRoad}) can't/shouldn't be moved */
748
792
  override move(): never { return this.error() }
749
- /** @deprecated System-level resources (UnusableRoad) can't/shouldn't be moved */
793
+ /** @deprecated System-level resources ({@link UnusableRoad}) can't/shouldn't be moved */
750
794
  override moveSync(): never { return this.error() }
751
- /** @deprecated System-level resources (UnusableRoad) can't/shouldn't be copied */
795
+ /** @deprecated System-level resources ({@link UnusableRoad}) can't/shouldn't be copied */
752
796
  override copy(): never { return this.error() }
753
- /** @deprecated System-level resources (UnusableRoad) can't/shouldn't be copied */
797
+ /** @deprecated System-level resources ({@link UnusableRoad}) can't/shouldn't be copied */
754
798
  override copySync(): never { return this.error() }
755
- /** @deprecated System-level resources (UnusableRoad) can't/shouldn't be renamed */
799
+ /** @deprecated System-level resources ({@link UnusableRoad}) can't/shouldn't be renamed */
756
800
  override rename(): never { return this.error() }
757
- /** @deprecated System-level resources (UnusableRoad) can't/shouldn't be renamed */
801
+ /** @deprecated System-level resources ({@link UnusableRoad}) can't/shouldn't be renamed */
758
802
  override renameSync(): never { return this.error() }
759
-
760
803
  override isUnusable(): this is UnusableRoad { return true as const }
761
804
  }
762
805
  export class BlockDevice extends UnusableRoad {
763
- async check(): Promise<boolean> { try { return (await fp.lstat(this.isAt)).isBlockDevice() } catch { return false } }
764
- checkSync(): boolean { try { return fs.lstatSync(this.isAt).isBlockDevice() } catch { return false } }
806
+ async check(throwOnError_: boolean): Promise<boolean> { try { return (await fp.lstat(this.isAt)).isBlockDevice() } catch (e) { if (throwOnError_) throw e; return false } }
807
+ checkSync(throwOnError_: boolean): boolean { try { return fs.lstatSync(this.isAt).isBlockDevice() } catch (e) { if (throwOnError_) throw e; return false } }
765
808
  override isBlockDevice(): this is BlockDevice { return true as const }
766
809
  }
767
810
  export function blockDevice(...args: ConstructorParameters<typeof BlockDevice>): BlockDevice { return new BlockDevice(...args) }
768
811
  export class CharacterDevice extends UnusableRoad {
769
- async check(): Promise<boolean> { try { return (await fp.lstat(this.isAt)).isCharacterDevice() } catch { return false } }
770
- checkSync(): boolean { try { return fs.lstatSync(this.isAt).isCharacterDevice() } catch { return false } }
812
+ async check(throwOnError_: boolean): Promise<boolean> { try { return (await fp.lstat(this.isAt)).isCharacterDevice() } catch (e) { if (throwOnError_) throw e; return false } }
813
+ checkSync(throwOnError_: boolean): boolean { try { return fs.lstatSync(this.isAt).isCharacterDevice() } catch (e) { if (throwOnError_) throw e; return false } }
771
814
  override isCharacterDevice(): this is CharacterDevice { return true as const }
772
815
  }
773
816
  export function characterDevice(...args: ConstructorParameters<typeof CharacterDevice>): CharacterDevice { return new CharacterDevice(...args) }
774
817
  export class Fifo extends UnusableRoad {
775
- async check(): Promise<boolean> { try { return (await fp.lstat(this.isAt)).isFIFO() } catch { return false } }
776
- checkSync(): boolean { try { return fs.lstatSync(this.isAt).isFIFO() } catch { return false } }
818
+ async check(throwOnError_: boolean): Promise<boolean> { try { return (await fp.lstat(this.isAt)).isFIFO() } catch (e) { if (throwOnError_) throw e; return false } }
819
+ checkSync(throwOnError_: boolean): boolean { try { return fs.lstatSync(this.isAt).isFIFO() } catch (e) { if (throwOnError_) throw e; return false } }
777
820
  override isFifo(): this is Fifo { return true as const }
778
821
  }
779
822
  export function fifo(...args: ConstructorParameters<typeof Fifo>): Fifo { return new Fifo(...args) }
780
823
  export class Socket extends UnusableRoad {
781
- async check(): Promise<boolean> { try { return (await fp.lstat(this.isAt)).isSocket() } catch { return false } }
782
- checkSync(): boolean { try { return fs.lstatSync(this.isAt).isSocket() } catch { return false } }
824
+ async check(throwOnError_: boolean): Promise<boolean> { try { return (await fp.lstat(this.isAt)).isSocket() } catch (e) { if (throwOnError_) throw e; return false } }
825
+ checkSync(throwOnError_: boolean): boolean { try { return fs.lstatSync(this.isAt).isSocket() } catch (e) { if (throwOnError_) throw e; return false } }
783
826
  override isSocket(): this is Socket { return true as const }
784
827
  }
785
828
  export function socket(...args: ConstructorParameters<typeof Socket>): Socket { return new Socket(...args) }