@gesslar/toolkit 3.8.0 → 3.12.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.
@@ -10,11 +10,10 @@
10
10
 
11
11
  import path from "node:path"
12
12
 
13
- import {Data, Valid} from "../browser/index.js"
14
13
  import DirectoryObject from "./DirectoryObject.js"
15
14
  import FileObject from "./FileObject.js"
16
15
  import FS from "./FS.js"
17
- import Sass from "./Sass.js"
16
+ import Valid from "./Valid.js"
18
17
 
19
18
  /**
20
19
  * CappedDirectoryObject extends DirectoryObject with constraints that ensure
@@ -26,7 +25,10 @@ import Sass from "./Sass.js"
26
25
  * @augments DirectoryObject
27
26
  */
28
27
  export default class CappedDirectoryObject extends DirectoryObject {
28
+ #real
29
29
  #cap
30
+ #cappedParentPath
31
+ #cappedParent
30
32
 
31
33
  /**
32
34
  * Constructs a CappedDirectoryObject instance.
@@ -35,13 +37,16 @@ export default class CappedDirectoryObject extends DirectoryObject {
35
37
  * (virtual root). With a parent, the path is resolved relative to the parent's
36
38
  * cap using virtual path semantics (absolute paths treated as cap-relative).
37
39
  *
38
- * @param {string} dirPath - Directory path (becomes cap if no parent, else relative to parent's cap)
40
+ * @param {string} [directory="."] - Directory path (becomes cap if no parent, else relative to parent's cap, defaults to current directory)
39
41
  * @param {CappedDirectoryObject?} [parent] - Optional parent capped directory
40
- * @param {boolean} [temporary=false] - Whether this is a temporary directory
41
- * @throws {Sass} If path is empty
42
42
  * @throws {Sass} If parent is provided but not a CappedDirectoryObject
43
43
  * @throws {Sass} If the resulting path would escape the cap
44
44
  * @example
45
+ * // Create new capped directory at current directory
46
+ * const cwd = new CappedDirectoryObject()
47
+ * // path: process.cwd(), cap: process.cwd()
48
+ *
49
+ * @example
45
50
  * // Create new capped directory
46
51
  * const cache = new CappedDirectoryObject("/home/user/.cache")
47
52
  * // path: /home/user/.cache, cap: /home/user/.cache
@@ -56,153 +61,84 @@ export default class CappedDirectoryObject extends DirectoryObject {
56
61
  * const config = new CappedDirectoryObject("/etc/config", cache)
57
62
  * // path: /home/user/.cache/etc/config, cap: /home/user/.cache
58
63
  */
59
- constructor(dirPath, parent=null, temporary=false) {
60
- Valid.type(dirPath, "String")
61
- Valid.assert(dirPath.length > 0, "Path must not be empty.")
62
-
63
- // Validate parent using inheritance-aware type checking
64
- if(parent !== null && !Data.isType(parent, "CappedDirectoryObject")) {
65
- throw Sass.new(`Parent must be null or a CappedDirectoryObject instance, got ${Data.typeOf(parent)}`)
66
- }
67
-
68
- let cap
69
- let resolvedPath
70
-
71
- if(!parent) {
72
- // No parent: dirPath becomes both the directory and the cap
73
- cap = path.resolve(dirPath)
74
- resolvedPath = cap
75
- } else {
76
- // With parent: inherit cap and resolve dirPath relative to it
77
- cap = parent.#cap
78
-
79
- // Use real path for filesystem operations
80
- const parentPath = parent.realPath || parent.path
81
- const capResolved = path.resolve(cap)
82
-
83
- let targetPath
84
-
85
- // If absolute, treat as virtual path relative to cap (strip leading /)
86
- if(path.isAbsolute(dirPath)) {
87
- const relative = dirPath.replace(/^[/\\]+/, "")
88
- targetPath = relative ? path.join(capResolved, relative) : capResolved
89
- } else {
90
- // Relative path - resolve from parent directory
91
- targetPath = FS.resolvePath(parentPath, dirPath)
92
- }
64
+ constructor(directory, source=null) {
65
+ Valid.type(source, "Null|CappedDirectoryObject")
93
66
 
94
- // Resolve to absolute path (handles .. and .)
95
- const resolved = path.resolve(targetPath)
67
+ directory ||= "."
96
68
 
97
- // Clamp to cap boundary - cannot escape above cap
98
- if(!resolved.startsWith(capResolved)) {
99
- // Path tried to escape - clamp to cap root
100
- resolvedPath = capResolved
101
- } else {
102
- resolvedPath = resolved
103
- }
104
- }
69
+ const baseLocalPath = source?.path ?? "/"
70
+ const baseRealPath = source?.real.path ?? directory
105
71
 
106
- // Call parent constructor with the path
107
- super(resolvedPath, temporary)
72
+ if(source && directory.startsWith("/"))
73
+ directory = directory.slice(1)
108
74
 
109
- // Store the cap AFTER calling super()
110
- this.#cap = cap
75
+ // Find out what directory means to the basePath
76
+ const realResolved = FS.resolvePath(baseRealPath, directory)
77
+ const localResolved = source
78
+ ? FS.resolvePath(baseLocalPath, directory)
79
+ : path.parse(path.resolve("")).root
111
80
 
112
- // Validate that this path is within the cap
113
- this.#validateCapPath()
114
- }
81
+ super(localResolved)
115
82
 
116
- /**
117
- * Validates that the directory path is within the cap directory tree.
118
- *
119
- * @private
120
- * @throws {Sass} If the path is not within the cap directory
121
- */
122
- #validateCapPath() {
123
- const cap = this.#cap
124
- const resolved = path.resolve(this.#realPath)
125
- const capResolved = path.resolve(cap)
83
+ this.#real = new DirectoryObject(realResolved)
84
+ this.#cap = source?.cap ?? this
126
85
 
127
- // Check if the resolved path starts with the cap directory
128
- if(!resolved.startsWith(capResolved)) {
129
- throw Sass.new(
130
- `Path '${this.#realPath}' is not within the cap directory '${cap}'`
131
- )
86
+ if(source) {
87
+ this.#cappedParent = source
88
+ this.#cappedParentPath = source.path
89
+ } else {
90
+ this.#cappedParent = null
91
+ this.#cappedParentPath = null
132
92
  }
133
93
  }
134
94
 
135
95
  /**
136
- * Re-caps this directory to itself, making it the new root of the capped tree.
137
- * This is a protected method intended for use by subclasses like TempDirectoryObject.
96
+ * Creates a CappedDirectoryObject from the current working directory.
97
+ * This is useful when working with pnpx or other tools where you need to
98
+ * cap at the project's root directory determined at runtime.
138
99
  *
139
- * @protected
100
+ * @returns {CappedDirectoryObject} A CappedDirectoryObject capped at the current working directory
101
+ * @example
102
+ * // When using pnpx or similar tools
103
+ * const projectRoot = CappedDirectoryObject.fromCwd()
104
+ * const srcDir = projectRoot.getDirectory("src")
105
+ * // srcDir is capped at the project root
140
106
  */
141
- _recapToSelf() {
142
- this.#cap = this.#realPath
107
+ static fromCwd() {
108
+ return new this(process.cwd())
143
109
  }
144
110
 
145
111
  /**
146
- * Returns the cap path for this directory.
112
+ * Indicates whether this directory is capped (constrained to a specific tree).
113
+ * Always returns true for CappedDirectoryObject instances.
147
114
  *
148
- * @returns {string} The cap directory path
149
- */
150
- get cap() {
151
- return this.#cap
152
- }
153
-
154
- /**
155
- * Returns whether this directory is capped.
115
+ * @returns {boolean} True for all CappedDirectoryObject instances
116
+ * @example
117
+ * const capped = new TempDirectoryObject("myapp")
118
+ * console.log(capped.isCapped) // true
156
119
  *
157
- * @returns {boolean} Always true for CappedDirectoryObject instances
120
+ * const regular = new DirectoryObject("/tmp")
121
+ * console.log(regular.isCapped) // false
158
122
  */
159
- get capped() {
123
+ get isCapped() {
160
124
  return true
161
125
  }
162
126
 
163
127
  /**
164
- * Returns the real filesystem path (for internal and subclass use).
165
- *
166
- * @protected
167
- * @returns {string} The actual filesystem path
168
- */
169
- get realPath() {
170
- return super.path
171
- }
172
-
173
- /**
174
- * Private alias for realPath (for use in private methods).
128
+ * Returns the cap (root) of the capped directory tree.
129
+ * For root CappedDirectoryObject instances, returns itself.
130
+ * For children, returns the inherited cap from the parent chain.
175
131
  *
176
- * @private
177
- * @returns {string} The actual filesystem path
178
- */
179
- get #realPath() {
180
- return this.realPath
181
- }
182
-
183
- /**
184
- * Returns the virtual path relative to the cap.
185
- * This is the default path representation in the capped environment.
186
- * Use `.real.path` to access the actual filesystem path.
187
- *
188
- * @returns {string} Path relative to cap, or "/" if at cap root
132
+ * @returns {CappedDirectoryObject} The cap directory object (root of the capped tree)
189
133
  * @example
190
134
  * const temp = new TempDirectoryObject("myapp")
191
- * const subdir = temp.getDirectory("data/cache")
192
- * console.log(subdir.path) // "/data/cache" (virtual, relative to cap)
193
- * console.log(subdir.real.path) // "/tmp/myapp-ABC123/data/cache" (actual filesystem)
135
+ * console.log(temp.cap === temp) // true (root is its own cap)
136
+ *
137
+ * const subdir = temp.getDirectory("data")
138
+ * console.log(subdir.cap === temp) // true (child inherits parent's cap)
194
139
  */
195
- get path() {
196
- const capResolved = path.resolve(this.#cap)
197
- const relative = path.relative(capResolved, this.#realPath)
198
-
199
- // If at cap root or empty, return "/"
200
- if(!relative || relative === ".") {
201
- return "/"
202
- }
203
-
204
- // Return with leading slash to indicate it's cap-relative
205
- return "/" + relative.split(path.sep).join("/")
140
+ get cap() {
141
+ return this.#cap
206
142
  }
207
143
 
208
144
  /**
@@ -224,7 +160,7 @@ export default class CappedDirectoryObject extends DirectoryObject {
224
160
  * subdir.real.parent // Can traverse outside the cap
225
161
  */
226
162
  get real() {
227
- return new DirectoryObject(this.#realPath)
163
+ return this.#real
228
164
  }
229
165
 
230
166
  /**
@@ -242,61 +178,31 @@ export default class CappedDirectoryObject extends DirectoryObject {
242
178
  * console.log(capped.parent) // null (at cap root)
243
179
  */
244
180
  get parent() {
245
- const capResolved = path.resolve(this.#cap)
246
-
247
- // If we're at the cap, return null (cap is the "root")
248
- if(this.#realPath === capResolved) {
249
- return null
250
- }
251
-
252
- // Compute parent's real path
253
- const parentPath = path.dirname(this.#realPath)
254
- const isRoot = parentPath === this.#realPath
255
-
256
- if(isRoot) {
257
- return null
258
- }
259
-
260
- // Compute relative path from current to parent (just "..")
261
- // Then use getDirectory to create the parent, which preserves the class type
262
- return this.getDirectory("..")
181
+ return this.#cappedParent
263
182
  }
264
183
 
265
184
  /**
266
- * Returns the URL with virtual path (cap-relative).
185
+ * Returns the path of the parent directory.
186
+ * Returns null if this directory is at the cap root (no parent).
187
+ *
188
+ * @returns {string|null} The parent directory path, or null if at cap root
189
+ * @example
190
+ * const temp = new TempDirectoryObject("myapp")
191
+ * console.log(temp.parentPath) // null (at cap root)
267
192
  *
268
- * @returns {URL} Virtual URL
193
+ * const subdir = temp.getDirectory("data")
194
+ * console.log(subdir.parentPath) // "/data" or similar (parent's virtual path)
269
195
  */
270
- get url() {
271
- return new URL(FS.pathToUri(this.path))
196
+ get parentPath() {
197
+ return this.#cappedParentPath
272
198
  }
273
199
 
274
200
  /**
275
- * Returns JSON representation with virtual paths and .real escape hatch.
201
+ * Returns a JSON representation of the DirectoryObject.
276
202
  *
277
- * @returns {object} JSON representation
203
+ * @returns {object} JSON representation of the DirectoryObject
278
204
  */
279
205
  toJSON() {
280
- const capResolved = path.resolve(this.#cap)
281
- let parentPath
282
-
283
- if(this.#realPath === capResolved) {
284
- // At cap root, no parent
285
- parentPath = null
286
- } else {
287
- // Compute parent's virtual path
288
- const parentReal = path.dirname(this.#realPath)
289
- const relative = path.relative(capResolved, parentReal)
290
-
291
- // If parent is cap root or empty, return "/"
292
- if(!relative || relative === ".") {
293
- parentPath = "/"
294
- } else {
295
- // Return parent's virtual path with leading slash
296
- parentPath = "/" + relative.split(path.sep).join("/")
297
- }
298
- }
299
-
300
206
  return {
301
207
  supplied: this.supplied,
302
208
  path: this.path,
@@ -306,260 +212,12 @@ export default class CappedDirectoryObject extends DirectoryObject {
306
212
  extension: this.extension,
307
213
  isFile: this.isFile,
308
214
  isDirectory: this.isDirectory,
309
- parent: parentPath,
310
- root: this.root.path,
311
- real: this.real.toJSON()
312
- }
313
- }
314
-
315
- /**
316
- * Generator that walks up the directory tree, stopping at the cap.
317
- * Yields parent directories from current up to (and including) the cap root.
318
- *
319
- * @returns {Generator<DirectoryObject>} Generator yielding parent DirectoryObject instances
320
- * @example
321
- * const capped = new TempDirectoryObject("myapp")
322
- * const deep = capped.getDirectory("data").getDirectory("files")
323
- * for(const parent of deep.walkUp) {
324
- * console.log(parent.path)
325
- * // .../myapp-ABC123/data/files
326
- * // .../myapp-ABC123/data
327
- * // .../myapp-ABC123 (stops at cap)
328
- * }
329
- */
330
- *#walkUpCapped() {
331
- const capResolved = path.resolve(this.#cap)
332
-
333
- // Build trail from real path
334
- const trail = this.#realPath.split(path.sep).filter(Boolean)
335
- const curr = [...trail]
336
-
337
- while(curr.length > 0) {
338
- const joined = path.sep + curr.join(path.sep)
339
-
340
- // Don't yield anything beyond the cap
341
- if(!joined.startsWith(capResolved)) {
342
- break
343
- }
344
-
345
- // Yield plain DirectoryObject with real path
346
- yield new DirectoryObject(joined, this.temporary)
347
-
348
- // Stop after yielding the cap
349
- if(joined === capResolved) {
350
- break
351
- }
352
-
353
- curr.pop()
354
- }
355
- }
356
-
357
- /**
358
- * Returns a generator that walks up to the cap.
359
- *
360
- * @returns {Generator<DirectoryObject>} Generator yielding parent directories
361
- */
362
- get walkUp() {
363
- return this.#walkUpCapped()
364
- }
365
-
366
- /**
367
- * Creates a new CappedDirectoryObject by extending this directory's path.
368
- *
369
- * All paths are coerced to remain within the cap directory tree:
370
- * - Absolute paths (e.g., "/foo") are treated as relative to the cap
371
- * - Parent traversal ("..") is allowed but clamped at the cap boundary
372
- * - The cap acts as the virtual root directory
373
- *
374
- * @param {string} newPath - The path to resolve (can be absolute or contain ..)
375
- * @returns {CappedDirectoryObject} A new CappedDirectoryObject with the coerced path
376
- * @example
377
- * const capped = new TempDirectoryObject("myapp")
378
- * const subDir = capped.getDirectory("data")
379
- * console.log(subDir.path) // "/tmp/myapp-ABC123/data"
380
- *
381
- * @example
382
- * // Absolute paths are relative to cap
383
- * const abs = capped.getDirectory("/foo/bar")
384
- * console.log(abs.path) // "/tmp/myapp-ABC123/foo/bar"
385
- *
386
- * @example
387
- * // Excessive .. traversal clamps to cap
388
- * const up = capped.getDirectory("../../../etc/passwd")
389
- * console.log(up.path) // "/tmp/myapp-ABC123" (clamped to cap)
390
- */
391
- getDirectory(newPath) {
392
- Valid.type(newPath, "String")
393
-
394
- // Fast path: if it's a simple name (no separators, not absolute, no ..)
395
- // use the subclass constructor directly to preserve type
396
- const isSimpleName = !path.isAbsolute(newPath) &&
397
- !newPath.includes("/") &&
398
- !newPath.includes("\\") &&
399
- !newPath.includes("..")
400
-
401
- if(isSimpleName) {
402
- // Both CappedDirectoryObject and subclasses use same signature now
403
- return new this.constructor(newPath, this, this.temporary)
404
- }
405
-
406
- // Complex path - handle coercion
407
- const capResolved = path.resolve(this.#cap)
408
- let targetPath
409
-
410
- // If absolute, treat as relative to cap (virtual root)
411
- if(path.isAbsolute(newPath)) {
412
- // Strip leading slashes to make relative
413
- const relative = newPath.replace(/^[/\\]+/, "")
414
-
415
- // Join with cap (unless empty, which means cap root)
416
- targetPath = relative ? path.join(capResolved, relative) : capResolved
417
- } else {
418
- // Relative path - resolve from current directory
419
- targetPath = FS.resolvePath(this.#realPath, newPath)
420
- }
421
-
422
- // Resolve to absolute path (handles .. and .)
423
- const resolved = path.resolve(targetPath)
424
-
425
- // Coerce: if path escaped cap, clamp to cap boundary
426
- const coerced = resolved.startsWith(capResolved)
427
- ? resolved
428
- : capResolved
429
-
430
- // Compute path relative to cap for reconstruction
431
- const relativeToCap = path.relative(capResolved, coerced)
432
-
433
- // If we're at the cap root, return cap root directory
434
- if(!relativeToCap || relativeToCap === ".") {
435
- return this.#createCappedAtRoot()
436
- }
437
-
438
- // Build directory by traversing segments from cap
439
- return this.#buildDirectoryFromRelativePath(relativeToCap)
440
- }
441
-
442
- /**
443
- * Creates a CappedDirectoryObject at the cap root.
444
- * Can be overridden by subclasses that have different root semantics.
445
- *
446
- * @private
447
- * @returns {CappedDirectoryObject} Directory object at cap root
448
- */
449
- #createCappedAtRoot() {
450
- // Create a base CappedDirectoryObject at the cap path
451
- // This works for direct usage of CappedDirectoryObject
452
- // Subclasses may need to override if they have special semantics
453
- return new CappedDirectoryObject(this.#cap, null, this.temporary)
454
- }
455
-
456
- /**
457
- * Builds a directory by traversing path segments from cap.
458
- *
459
- * @private
460
- * @param {string} relativePath - Path relative to cap
461
- * @returns {CappedDirectoryObject} The directory at the final path
462
- */
463
- #buildDirectoryFromRelativePath(relativePath) {
464
- const segments = relativePath.split(path.sep).filter(Boolean)
465
-
466
- // Start at cap root
467
- let current = this.#createCappedAtRoot()
468
-
469
- // Traverse each segment, using constructor to preserve class type
470
- for(const segment of segments) {
471
- // Use simple name constructor to preserve subclass type
472
- // Works for both CappedDirectoryObject and TempDirectoryObject
473
- current = new this.constructor(segment, current, this.temporary)
474
- }
475
-
476
- return current
477
- }
478
-
479
- /**
480
- * Creates a new FileObject by extending this directory's path.
481
- *
482
- * All paths are coerced to remain within the cap directory tree:
483
- * - Absolute paths (e.g., "/config.json") are treated as relative to the cap
484
- * - Parent traversal ("..") is allowed but clamped at the cap boundary
485
- * - The cap acts as the virtual root directory
486
- *
487
- * @param {string} filename - The filename to resolve (can be absolute or contain ..)
488
- * @returns {FileObject} A new FileObject with the coerced path
489
- * @example
490
- * const capped = new TempDirectoryObject("myapp")
491
- * const file = capped.getFile("config.json")
492
- * console.log(file.path) // "/tmp/myapp-ABC123/config.json"
493
- *
494
- * @example
495
- * // Absolute paths are relative to cap
496
- * const abs = capped.getFile("/data/config.json")
497
- * console.log(abs.path) // "/tmp/myapp-ABC123/data/config.json"
498
- *
499
- * @example
500
- * // Excessive .. traversal clamps to cap
501
- * const up = capped.getFile("../../../etc/passwd")
502
- * console.log(up.path) // "/tmp/myapp-ABC123/passwd" (clamped to cap)
503
- */
504
- getFile(filename) {
505
- Valid.type(filename, "String")
506
-
507
- // Fast path: if it's a simple filename (no separators, not absolute, no ..)
508
- // use this as the parent directly
509
- const isSimpleName = !path.isAbsolute(filename) &&
510
- !filename.includes("/") &&
511
- !filename.includes("\\") &&
512
- !filename.includes("..")
513
-
514
- if(isSimpleName) {
515
- // Simple filename - create directly with this as parent
516
- return new FileObject(filename, this)
517
- }
518
-
519
- // Complex path - handle coercion
520
- const capResolved = path.resolve(this.#cap)
521
- let targetPath
522
-
523
- // If absolute, treat as relative to cap (virtual root)
524
- if(path.isAbsolute(filename)) {
525
- // Strip leading slashes to make relative
526
- const relative = filename.replace(/^[/\\]+/, "")
527
-
528
- // Join with cap
529
- targetPath = path.join(capResolved, relative)
530
- } else {
531
- // Relative path - resolve from current directory
532
- targetPath = FS.resolvePath(this.#realPath, filename)
533
- }
534
-
535
- // Resolve to absolute path (handles .. and .)
536
- const resolved = path.resolve(targetPath)
537
-
538
- // Coerce: if path escaped cap, clamp to cap boundary
539
- const coerced = resolved.startsWith(capResolved)
540
- ? resolved
541
- : capResolved
542
-
543
- // Extract directory and filename parts
544
- let fileDir = path.dirname(coerced)
545
- let fileBasename = path.basename(coerced)
546
-
547
- // Special case: if coerced is exactly the cap (file tried to escape),
548
- // the file should be placed at the cap root with just the filename
549
- if(coerced === capResolved) {
550
- // Extract just the filename from the original path
551
- fileBasename = path.basename(resolved)
552
- fileDir = capResolved
215
+ parent: this.parent,
216
+ parentPath: this.parentPath,
217
+ capped: this.isCapped,
218
+ cap: this.cap,
219
+ real: this.real
553
220
  }
554
-
555
- // Get or create the parent directory
556
- const relativeToCap = path.relative(capResolved, fileDir)
557
- const parentDir = !relativeToCap || relativeToCap === "."
558
- ? this.#createCappedAtRoot()
559
- : this.#buildDirectoryFromRelativePath(relativeToCap)
560
-
561
- // Create FileObject with parent directory
562
- return new FileObject(fileBasename, parentDir)
563
221
  }
564
222
 
565
223
  /**
@@ -577,20 +235,14 @@ export default class CappedDirectoryObject extends DirectoryObject {
577
235
  * @param {string} [pat=""] - Optional glob pattern
578
236
  * @returns {Promise<{files: Array<FileObject>, directories: Array}>} Directory contents
579
237
  */
580
- async read(pat="") {
581
- const {files, directories} = await this.real.read(pat)
582
-
583
- // Convert plain DirectoryObjects to CappedDirectoryObjects with same cap
584
- const cappedDirectories = directories.map(dir => {
585
- const name = dir.name
586
-
587
- return new this.constructor(name, this)
588
- })
238
+ async read(...arg) {
239
+ const {files, directories} = await this.real.read(...arg)
589
240
 
590
- // Recreate FileObjects with capped parent so they return virtual paths
591
- const cappedFiles = files.map(file => new FileObject(file.name, this))
241
+ // we need to re-cast
242
+ const recastDirs = directories.map(e => this.getDirectory(e.name))
243
+ const recastFiles = files.map(f => new FileObject(f.name, this))
592
244
 
593
- return {files: cappedFiles, directories: cappedDirectories}
245
+ return {files: recastFiles, directories: recastDirs}
594
246
  }
595
247
 
596
248
  /**
@@ -621,36 +273,4 @@ export default class CappedDirectoryObject extends DirectoryObject {
621
273
  async delete() {
622
274
  return await this.real.delete()
623
275
  }
624
-
625
- /**
626
- * Override remove to preserve temporary flag check.
627
- *
628
- * @returns {Promise<void>}
629
- */
630
- async remove() {
631
- if(!this.temporary)
632
- throw Sass.new("This is not a temporary directory.")
633
-
634
- const {files, directories} = await this.read()
635
-
636
- // Remove subdirectories recursively
637
- for(const dir of directories)
638
- await dir.remove()
639
-
640
- // Remove files
641
- for(const file of files)
642
- await file.delete()
643
-
644
- // Delete the now-empty directory
645
- await this.delete()
646
- }
647
-
648
- /**
649
- * Returns a string representation of the CappedDirectoryObject.
650
- *
651
- * @returns {string} string representation of the CappedDirectoryObject
652
- */
653
- toString() {
654
- return `[CappedDirectoryObject: ${this.path} (real: ${this.#realPath})]`
655
- }
656
276
  }