instrumentality 0.0.6 → 0.0.8
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 +2 -2
- package/dist/base.d.ts +11 -12
- package/dist/base.d.ts.map +1 -1
- package/dist/base.js +23 -39
- package/dist/dom.d.ts +1 -6
- package/dist/dom.d.ts.map +1 -1
- package/dist/dom.js +1 -6
- package/dist/road.d.ts +136 -92
- package/dist/road.d.ts.map +1 -1
- package/dist/road.js +441 -313
- package/package.json +5 -3
- package/src/base.ts +22 -43
- package/src/dom.ts +1 -10
- package/src/road.ts +400 -350
package/dist/road.js
CHANGED
|
@@ -1,25 +1,24 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as cr from "node:crypto";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import { constants as fsc } from "node:fs";
|
|
4
4
|
import * as fp from "node:fs/promises";
|
|
5
5
|
import * as ph from "node:path";
|
|
6
6
|
import * as os from "node:os";
|
|
7
|
-
import * as cr from "node:crypto";
|
|
8
7
|
import { on } from "node:events";
|
|
9
|
-
import
|
|
10
|
-
/** Subclass of {@link
|
|
11
|
-
export class
|
|
8
|
+
import { InsErr } from "./base.js";
|
|
9
|
+
/** Subclass of {@link InsErr} that represents an error thrown from this specific module of the library */
|
|
10
|
+
export class Err extends InsErr {
|
|
12
11
|
name = "Instrumentality-Road-Error";
|
|
13
12
|
}
|
|
14
|
-
export {
|
|
13
|
+
export { Err as RoadError, Err as RdErr };
|
|
15
14
|
/**
|
|
16
15
|
* Returns the constructor function corresponding to the file mode (statmode).
|
|
17
16
|
*
|
|
18
|
-
* @param statmode_ The file mode to check.
|
|
17
|
+
* @param statmode_ The file mode or {@link fs.Dirent} to check.
|
|
19
18
|
* @returns The constructor function corresponding to the road type (e.g., {@link File}, {@link Folder}, etc.).
|
|
20
|
-
* @throws If the file mode is unknown, throws a {@link
|
|
19
|
+
* @throws If the file mode is unknown, throws a {@link Err}.
|
|
21
20
|
*/
|
|
22
|
-
export function
|
|
21
|
+
export function resolveStat(statmode_) {
|
|
23
22
|
switch (statmode_ & fsc.S_IFMT) {
|
|
24
23
|
case fsc.S_IFREG: return File;
|
|
25
24
|
case fsc.S_IFDIR: return Folder;
|
|
@@ -28,9 +27,36 @@ export function resolveMode(statmode_) {
|
|
|
28
27
|
case fsc.S_IFLNK: return SymbolicLink;
|
|
29
28
|
case fsc.S_IFIFO: return Fifo;
|
|
30
29
|
case fsc.S_IFSOCK: return Socket;
|
|
31
|
-
default: throw new
|
|
30
|
+
default: throw new Err(`Unknown mode type ${statmode_} (statmode is most likely corrupted)`);
|
|
32
31
|
}
|
|
33
32
|
}
|
|
33
|
+
export { resolveStat as resStat };
|
|
34
|
+
/**
|
|
35
|
+
* Returns the constructor function corresponding to the type of the given {@link fs.Dirent}.
|
|
36
|
+
*
|
|
37
|
+
* @param dirent The directory entry to check.
|
|
38
|
+
* @returns The constructor function corresponding to the road type (e.g., {@link File}, {@link Folder}, etc.).
|
|
39
|
+
* @throws If the directory entry type is unknown, throws a {@link Err}.
|
|
40
|
+
*/
|
|
41
|
+
export function resolveDirent(dirent) {
|
|
42
|
+
// Order by likelihood: files/dicts are most common, followed by symbolic links
|
|
43
|
+
if (dirent.isFile())
|
|
44
|
+
return File;
|
|
45
|
+
if (dirent.isDirectory())
|
|
46
|
+
return Folder;
|
|
47
|
+
if (dirent.isSymbolicLink())
|
|
48
|
+
return SymbolicLink;
|
|
49
|
+
if (dirent.isBlockDevice())
|
|
50
|
+
return BlockDevice;
|
|
51
|
+
if (dirent.isCharacterDevice())
|
|
52
|
+
return CharacterDevice;
|
|
53
|
+
if (dirent.isFIFO())
|
|
54
|
+
return Fifo;
|
|
55
|
+
if (dirent.isSocket())
|
|
56
|
+
return Socket;
|
|
57
|
+
throw new Err(`Unknown dirent type for ${dirent.name}`);
|
|
58
|
+
}
|
|
59
|
+
export { resolveDirent as resDirent };
|
|
34
60
|
/**
|
|
35
61
|
* Creates the appropriate subclass of {@link Road} based on the file mode of the specified path.
|
|
36
62
|
*
|
|
@@ -39,16 +65,18 @@ export function resolveMode(statmode_) {
|
|
|
39
65
|
* @throws If {@link fp.lstat}/{@link fs.lstatSync} fails to retrieved the status of {@link path_}.
|
|
40
66
|
*/
|
|
41
67
|
export async function factory(path_) {
|
|
42
|
-
return new (
|
|
68
|
+
return new (resolveStat((await fp.lstat(path_)).mode))(path_, false);
|
|
43
69
|
}
|
|
70
|
+
export { factory as fac, factory as mk };
|
|
44
71
|
/** Sync version of {@link factory}. */
|
|
45
72
|
export function factorySync(path_) {
|
|
46
|
-
return new (
|
|
73
|
+
return new (resolveStat(fs.lstatSync(path_).mode))(path_, false);
|
|
47
74
|
}
|
|
75
|
+
export { factorySync as facSync, factorySync as mkSync };
|
|
48
76
|
/**
|
|
49
77
|
* A map that keeps track of locked roads to prevent concurrent modifications.
|
|
50
78
|
*
|
|
51
|
-
* @key The absolute path of the road that is currently locked.
|
|
79
|
+
* @key The **absolute** and **normalized** (**resolved**) path of the road that is currently locked.
|
|
52
80
|
* @value A promise that resolves when the lock on the road is released.
|
|
53
81
|
*
|
|
54
82
|
* @remarks The map is initialized lazily when the first lock is created to minimize import-time side effects.
|
|
@@ -84,82 +112,78 @@ export class Road {
|
|
|
84
112
|
* @param path_ Any path-like string that can be resolved to an absolute path. It will be resolved to an absolute path using {@link ph.resolve}.
|
|
85
113
|
* @param typeCheck_ If true, the constructor will check if the path corresponds to the expected type of road (e.g., file, folder, etc.) and throw an error if it doesn't. If false, no type checking will be performed.
|
|
86
114
|
*
|
|
87
|
-
* @throws If {@link typeCheck_} is true and the path does not correspond to the expected type of road, a {@link
|
|
115
|
+
* @throws If {@link typeCheck_} is true and the path does not correspond to the expected type of road, a {@link Err} will be thrown.
|
|
88
116
|
*/
|
|
89
117
|
constructor(path_, typeCheck_) {
|
|
90
118
|
this.pointsTo = ph.resolve(path_);
|
|
91
119
|
if (typeCheck_ && !this.checkSync())
|
|
92
|
-
throw new
|
|
120
|
+
throw new Err(`Type mismatch: '${this.isAt}'`);
|
|
121
|
+
}
|
|
122
|
+
/** @returns An instance of {@link Folder} representing the parent directory of the current road. */
|
|
123
|
+
parent() { return new Folder(ph.dirname(this.isAt), false); }
|
|
124
|
+
/**
|
|
125
|
+
* An async generator that yields the ancestors of the current road, starting from its parent and moving up the directory tree until it reaches the root.
|
|
126
|
+
*
|
|
127
|
+
* @yields Each ancestor folder as a {@link Folder} instance.
|
|
128
|
+
*/
|
|
129
|
+
*ancestorsIt() {
|
|
130
|
+
let current = this.parent();
|
|
131
|
+
let parent = current.parent();
|
|
132
|
+
while (current.isAt !== parent.isAt) {
|
|
133
|
+
yield current;
|
|
134
|
+
current = parent;
|
|
135
|
+
parent = current.parent();
|
|
136
|
+
}
|
|
93
137
|
}
|
|
138
|
+
/** @returns An array of {@link Folder} instances representing the ancestors of the current road. */
|
|
139
|
+
ancestors() { return [...this.ancestorsIt()]; }
|
|
94
140
|
/**
|
|
95
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.
|
|
96
142
|
*
|
|
97
|
-
* @param cb_ A callback function that will be called when the lock is released. This is used internally to manage the lock state.
|
|
98
143
|
* @returns An object with a dispose method that releases the lock when called.
|
|
99
|
-
* @throws If the road is immutable, a {@link
|
|
144
|
+
* @throws If the road is immutable, a {@link Err} will be thrown.
|
|
100
145
|
*
|
|
101
|
-
* @remarks This method MUST be used with a `using` statement to ensure that the lock is released properly. Failing to do so
|
|
102
|
-
* 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 (
|
|
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.
|
|
103
150
|
*/
|
|
104
|
-
async lock(
|
|
151
|
+
async lock() {
|
|
105
152
|
if (!this.mutable)
|
|
106
|
-
throw new
|
|
153
|
+
throw new Err(`Road to '${this.isAt}' is immutable.`);
|
|
107
154
|
lockedRoads ??= new Map();
|
|
155
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
156
|
+
const previous = lockedRoads.get(this.isAt);
|
|
157
|
+
lockedRoads.set(this.isAt, promise);
|
|
108
158
|
const isAt = this.isAt;
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
[Symbol.dispose]() {
|
|
113
|
-
cb_();
|
|
114
|
-
lockedRoads.delete(isAt);
|
|
115
|
-
},
|
|
116
|
-
async [Symbol.asyncDispose]() {
|
|
117
|
-
cb_();
|
|
159
|
+
const dispose = () => {
|
|
160
|
+
resolve();
|
|
161
|
+
if (lockedRoads.get(isAt) === promise)
|
|
118
162
|
lockedRoads.delete(isAt);
|
|
119
|
-
}
|
|
120
163
|
};
|
|
164
|
+
await previous;
|
|
165
|
+
return { [Symbol.dispose]: dispose, [Symbol.asyncDispose]: dispose };
|
|
121
166
|
}
|
|
122
167
|
/**
|
|
123
168
|
* Sync version of {@link lock}.
|
|
124
|
-
* @throws
|
|
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.
|
|
125
170
|
*/
|
|
126
|
-
lockSync(
|
|
171
|
+
lockSync() {
|
|
127
172
|
if (!this.mutable)
|
|
128
|
-
throw new
|
|
173
|
+
throw new Err(`Road to '${this.isAt}' is immutable.`);
|
|
129
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);
|
|
130
179
|
const isAt = this.isAt;
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
return {
|
|
135
|
-
[Symbol.dispose]() {
|
|
136
|
-
lockedRoads.delete(isAt);
|
|
137
|
-
cb_();
|
|
138
|
-
},
|
|
139
|
-
async [Symbol.asyncDispose]() {
|
|
180
|
+
const dispose = () => {
|
|
181
|
+
resolve();
|
|
182
|
+
if (lockedRoads.get(isAt) === promise)
|
|
140
183
|
lockedRoads.delete(isAt);
|
|
141
|
-
cb_();
|
|
142
|
-
}
|
|
143
184
|
};
|
|
185
|
+
return { [Symbol.dispose]: dispose, [Symbol.asyncDispose]: dispose };
|
|
144
186
|
}
|
|
145
|
-
/** @returns An instance of {@link Folder} representing the parent directory of the current road. */
|
|
146
|
-
parent() { return new Folder(ph.dirname(this.isAt), false); }
|
|
147
|
-
/**
|
|
148
|
-
* An async generator that yields the ancestors of the current road, starting from its parent and moving up the directory tree until it reaches the root.
|
|
149
|
-
*
|
|
150
|
-
* @yields Each ancestor folder as a {@link Folder} instance.
|
|
151
|
-
*/
|
|
152
|
-
*ancestorsIt() {
|
|
153
|
-
let current = this.parent();
|
|
154
|
-
let parent = current.parent();
|
|
155
|
-
while (current.isAt !== parent.isAt) {
|
|
156
|
-
yield current;
|
|
157
|
-
current = parent;
|
|
158
|
-
parent = current.parent();
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
/** @returns An array of {@link Folder} instances representing the ancestors of the current road. */
|
|
162
|
-
ancestors() { return [...this.ancestorsIt()]; }
|
|
163
187
|
/**
|
|
164
188
|
* Watches the current entry for changes and resolves when the entry becomes accessible (i.e., exists and can be accessed).
|
|
165
189
|
*
|
|
@@ -215,10 +239,50 @@ export class Road {
|
|
|
215
239
|
lstat() { return fp.lstat(this.isAt); }
|
|
216
240
|
/** @returns The result of {@link fs.lstatSync} for the current entry. */
|
|
217
241
|
lstatSync() { return fs.lstatSync(this.isAt); }
|
|
218
|
-
/**
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
242
|
+
/** Wrapper around {@link fp.rm} with locking. */
|
|
243
|
+
async delete() {
|
|
244
|
+
using _ = await this.lock();
|
|
245
|
+
await fp.rm(this.isAt, { recursive: true, force: true });
|
|
246
|
+
}
|
|
247
|
+
/** Wrapper around {@link fs.rmSync} with locking. */
|
|
248
|
+
deleteSync() {
|
|
249
|
+
using _ = this.lockSync();
|
|
250
|
+
fs.rmSync(this.isAt, { recursive: true, force: true });
|
|
251
|
+
}
|
|
252
|
+
async copy(into_, options_) {
|
|
253
|
+
const newPath = into_.join(this.name);
|
|
254
|
+
await fp.cp(this.isAt, newPath, { recursive: true, ...options_ });
|
|
255
|
+
return new this.constructor(newPath, false);
|
|
256
|
+
}
|
|
257
|
+
copySync(into_, options_) {
|
|
258
|
+
const newPath = into_.join(this.name);
|
|
259
|
+
fs.cpSync(this.isAt, newPath, { recursive: true, ...options_ });
|
|
260
|
+
return new this.constructor(newPath, false);
|
|
261
|
+
}
|
|
262
|
+
async move(into_) {
|
|
263
|
+
using _ = await this.lock();
|
|
264
|
+
const newPath = into_.join(this.name);
|
|
265
|
+
await fp.rename(this.isAt, newPath);
|
|
266
|
+
this.pointsTo = newPath;
|
|
267
|
+
}
|
|
268
|
+
moveSync(into_) {
|
|
269
|
+
using _ = this.lockSync();
|
|
270
|
+
const newPath = into_.join(this.name);
|
|
271
|
+
fs.renameSync(this.isAt, newPath);
|
|
272
|
+
this.pointsTo = newPath;
|
|
273
|
+
}
|
|
274
|
+
async rename(newName_) {
|
|
275
|
+
using _ = await this.lock();
|
|
276
|
+
const newPath = this.parent().join(newName_);
|
|
277
|
+
await fp.rename(this.isAt, newPath);
|
|
278
|
+
this.pointsTo = newPath;
|
|
279
|
+
}
|
|
280
|
+
renameSync(newName_) {
|
|
281
|
+
using _ = this.lockSync();
|
|
282
|
+
const newPath = this.parent().join(newName_);
|
|
283
|
+
fs.renameSync(this.isAt, newPath);
|
|
284
|
+
this.pointsTo = newPath;
|
|
285
|
+
}
|
|
222
286
|
/** Type narrowing for {@link File} (similar to `instanceof` without unnecessary runtime checks). */
|
|
223
287
|
isFile() { return false; }
|
|
224
288
|
/** Type narrowing for {@link Folder} (similar to `instanceof` without unnecessary runtime checks). */
|
|
@@ -227,10 +291,6 @@ export class Road {
|
|
|
227
291
|
isFolder() { return false; }
|
|
228
292
|
/** Type narrowing for {@link Folder} (similar to `instanceof` without unnecessary runtime checks). */
|
|
229
293
|
isDirectory() { return false; }
|
|
230
|
-
/** Type narrowing for {@link Folder} (similar to `instanceof` without unnecessary runtime checks). */
|
|
231
|
-
isDict() { return false; }
|
|
232
|
-
/** Type narrowing for {@link Folder} (similar to `instanceof` without unnecessary runtime checks). */
|
|
233
|
-
isDictionary() { return false; }
|
|
234
294
|
/** Type narrowing for {@link SymbolicLink} (similar to `instanceof` without unnecessary runtime checks). */
|
|
235
295
|
isSymlink() { return false; }
|
|
236
296
|
/** Type narrowing for {@link SymbolicLink} (similar to `instanceof` without unnecessary runtime checks). */
|
|
@@ -248,6 +308,13 @@ export class Road {
|
|
|
248
308
|
}
|
|
249
309
|
/** Subclass of {@link Road} that represents a file. */
|
|
250
310
|
export class File extends Road {
|
|
311
|
+
/**
|
|
312
|
+
* Creates a new file at the specified path if it does not already exist.
|
|
313
|
+
*
|
|
314
|
+
* @param at_ The path at which to create the file.
|
|
315
|
+
* @returns A promise that resolves to the newly created `File` instance.
|
|
316
|
+
* @throws if {@link fp.writeFile} throws.
|
|
317
|
+
*/
|
|
251
318
|
static async create(at_) {
|
|
252
319
|
try {
|
|
253
320
|
await fp.access(at_, fsc.W_OK);
|
|
@@ -257,6 +324,9 @@ export class File extends Road {
|
|
|
257
324
|
}
|
|
258
325
|
return new File(at_, true);
|
|
259
326
|
}
|
|
327
|
+
/** Alias for {@link File.create}. */
|
|
328
|
+
static mk = File.create;
|
|
329
|
+
/** Synchronous version of {@link File.create}. */
|
|
260
330
|
static createSync(at_) {
|
|
261
331
|
try {
|
|
262
332
|
fs.accessSync(at_, fs.constants.W_OK);
|
|
@@ -266,7 +336,11 @@ export class File extends Road {
|
|
|
266
336
|
}
|
|
267
337
|
return new File(at_, true);
|
|
268
338
|
}
|
|
339
|
+
/** Alias for {@link File.createSync}. */
|
|
340
|
+
static mkSync = File.createSync;
|
|
341
|
+
/** The file extension of this file, including the leading dot. */
|
|
269
342
|
get ext() { return ph.extname(this.isAt); }
|
|
343
|
+
/** The file name without its extension. */
|
|
270
344
|
get noExt() { return ph.basename(this.isAt, this.ext); }
|
|
271
345
|
async read(encoding_, flag_) {
|
|
272
346
|
if (encoding_)
|
|
@@ -280,16 +354,50 @@ export class File extends Road {
|
|
|
280
354
|
else
|
|
281
355
|
return fs.readFileSync(this.isAt);
|
|
282
356
|
}
|
|
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
|
+
}
|
|
373
|
+
}
|
|
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
|
+
}
|
|
283
392
|
async *itBuff(chunkSize_ = 64 * 1024, flags_ = 'r', mode_) {
|
|
284
393
|
const fd = await fp.open(this.isAt, flags_, mode_);
|
|
285
394
|
try {
|
|
286
395
|
const buffer = Buffer.alloc(chunkSize_);
|
|
287
396
|
let bytesRead;
|
|
288
397
|
do {
|
|
289
|
-
|
|
290
|
-
bytesRead = readResult.bytesRead;
|
|
398
|
+
bytesRead = (await fd.read(buffer, 0, chunkSize_, null)).bytesRead;
|
|
291
399
|
if (bytesRead > 0)
|
|
292
|
-
yield buffer.subarray(0, bytesRead);
|
|
400
|
+
yield Buffer.from(buffer.subarray(0, bytesRead));
|
|
293
401
|
} while (bytesRead === chunkSize_);
|
|
294
402
|
}
|
|
295
403
|
finally {
|
|
@@ -304,13 +412,73 @@ export class File extends Road {
|
|
|
304
412
|
do {
|
|
305
413
|
bytesRead = fs.readSync(fd, buffer, 0, chunkSize_, null);
|
|
306
414
|
if (bytesRead > 0)
|
|
307
|
-
yield buffer.subarray(0, bytesRead);
|
|
415
|
+
yield Buffer.from(buffer.subarray(0, bytesRead));
|
|
308
416
|
} while (bytesRead === chunkSize_);
|
|
309
417
|
}
|
|
310
418
|
finally {
|
|
311
419
|
fs.closeSync(fd);
|
|
312
420
|
}
|
|
313
421
|
}
|
|
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);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
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);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
carry += decoder.decode();
|
|
451
|
+
if (carry.length > 0)
|
|
452
|
+
yield carry.endsWith("\r") ? carry.slice(0, -1) : carry;
|
|
453
|
+
}
|
|
454
|
+
async hash(algorithm_ = "sha256", options_, encoding_) {
|
|
455
|
+
const hash = cr.createHash(algorithm_, options_);
|
|
456
|
+
for await (const chunk of this.itBuff())
|
|
457
|
+
hash.update(chunk);
|
|
458
|
+
return encoding_ ? hash.digest(encoding_) : hash.digest();
|
|
459
|
+
}
|
|
460
|
+
hashSync(algorithm_ = "sha256", options_, encoding_) {
|
|
461
|
+
const hash = cr.createHash(algorithm_, options_);
|
|
462
|
+
for (const chunk of this.itBuffSync())
|
|
463
|
+
hash.update(chunk);
|
|
464
|
+
return encoding_ ? hash.digest(encoding_) : hash.digest();
|
|
465
|
+
}
|
|
466
|
+
async size() { return (await this.lstat()).size; }
|
|
467
|
+
sizeSync() { return this.lstatSync().size; }
|
|
468
|
+
async writeAtomic(data_, options_) {
|
|
469
|
+
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
|
|
474
|
+
}
|
|
475
|
+
writeAtomicSync(data_, options_) {
|
|
476
|
+
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
|
|
481
|
+
}
|
|
314
482
|
async write(data_, options_) {
|
|
315
483
|
using _ = await this.lock();
|
|
316
484
|
await fp.writeFile(this.isAt, data_, options_);
|
|
@@ -327,122 +495,19 @@ export class File extends Road {
|
|
|
327
495
|
using _ = this.lockSync();
|
|
328
496
|
fs.appendFileSync(this.isAt, data_, options_);
|
|
329
497
|
}
|
|
330
|
-
async
|
|
331
|
-
|
|
332
|
-
await fp.rm(this.isAt, { force: true });
|
|
333
|
-
}
|
|
334
|
-
deleteSync() {
|
|
335
|
-
using _ = this.lockSync();
|
|
336
|
-
fs.rmSync(this.isAt, { force: true });
|
|
337
|
-
}
|
|
338
|
-
async move(into_) {
|
|
339
|
-
using _ = await this.lock();
|
|
340
|
-
const newPath = into_.join(this.name);
|
|
341
|
-
await fp.rename(this.isAt, newPath);
|
|
342
|
-
this.pointsTo = newPath;
|
|
498
|
+
async check() { try {
|
|
499
|
+
return (await fp.lstat(this.isAt)).isFile();
|
|
343
500
|
}
|
|
344
|
-
|
|
345
|
-
using _ = this.lockSync();
|
|
346
|
-
const newPath = into_.join(this.name);
|
|
347
|
-
fs.renameSync(this.isAt, newPath);
|
|
348
|
-
this.pointsTo = newPath;
|
|
349
|
-
}
|
|
350
|
-
async copy(into_) {
|
|
351
|
-
const newPath = into_.join(this.name);
|
|
352
|
-
await fp.copyFile(this.isAt, newPath);
|
|
353
|
-
return new File(newPath, false);
|
|
354
|
-
}
|
|
355
|
-
copySync(into_) {
|
|
356
|
-
const newPath = into_.join(this.name);
|
|
357
|
-
fs.copyFileSync(this.isAt, newPath);
|
|
358
|
-
return new File(newPath, false);
|
|
359
|
-
}
|
|
360
|
-
async rename(to_) {
|
|
361
|
-
using _ = await this.lock();
|
|
362
|
-
const newPath = this.parent().join(to_);
|
|
363
|
-
await fp.rename(this.isAt, newPath);
|
|
364
|
-
this.pointsTo = newPath;
|
|
365
|
-
}
|
|
366
|
-
renameSync(to_) {
|
|
367
|
-
using _ = this.lockSync();
|
|
368
|
-
const newPath = this.parent().join(to_);
|
|
369
|
-
fs.renameSync(this.isAt, newPath);
|
|
370
|
-
this.pointsTo = newPath;
|
|
371
|
-
}
|
|
372
|
-
async check() { return (await fp.lstat(this.isAt)).isFile(); }
|
|
373
|
-
checkSync() { return fs.lstatSync(this.isAt).isFile(); }
|
|
374
|
-
isFile() { return true; }
|
|
375
|
-
}
|
|
376
|
-
export async function hash(f_, algorithm_ = "sha256", options_, encoding_) {
|
|
377
|
-
const hash = cr.createHash(algorithm_, options_);
|
|
378
|
-
for await (const chunk of f_.itBuff())
|
|
379
|
-
hash.update(chunk);
|
|
380
|
-
return encoding_ ? hash.digest(encoding_) : hash.digest();
|
|
381
|
-
}
|
|
382
|
-
export function hashSync(f_, algorithm_ = "sha256", options_, encoding_) {
|
|
383
|
-
const hash = cr.createHash(algorithm_, options_);
|
|
384
|
-
for (const chunk of f_.itBuffSync())
|
|
385
|
-
hash.update(chunk);
|
|
386
|
-
return encoding_ ? hash.digest(encoding_) : hash.digest();
|
|
387
|
-
}
|
|
388
|
-
export async function streamHash(f_, algorithm_ = "sha256", options_, encoding_) {
|
|
389
|
-
const hash = cr.createHash(algorithm_, options_);
|
|
390
|
-
for await (const chunk of f_.itBuff())
|
|
391
|
-
hash.update(chunk);
|
|
392
|
-
return encoding_ ? hash.digest(encoding_) : hash.digest();
|
|
393
|
-
}
|
|
394
|
-
export function streamHashSync(f_, algorithm_ = "sha256", options_, encoding_) {
|
|
395
|
-
const hash = cr.createHash(algorithm_, options_);
|
|
396
|
-
for (const chunk of f_.itBuffSync())
|
|
397
|
-
hash.update(chunk);
|
|
398
|
-
return encoding_ ? hash.digest(encoding_) : hash.digest();
|
|
399
|
-
}
|
|
400
|
-
export async function* itLines(f_, options_ = { encoding: 'utf-8' }) {
|
|
401
|
-
const readStream = fs.createReadStream(f_.isAt, options_);
|
|
402
|
-
const rlInterface = rl.createInterface({ input: readStream, crlfDelay: Infinity });
|
|
403
|
-
try {
|
|
404
|
-
for await (const line of rlInterface)
|
|
405
|
-
yield line;
|
|
406
|
-
}
|
|
407
|
-
finally {
|
|
408
|
-
rlInterface.close();
|
|
409
|
-
readStream.destroy();
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
export async function fileSameAs(f1_, f2_) {
|
|
413
|
-
if (f1_.isAt === f2_.isAt)
|
|
414
|
-
return true;
|
|
415
|
-
else if ((await fp.lstat(f1_.isAt)).size !== (await fp.lstat(f2_.isAt)).size)
|
|
501
|
+
catch {
|
|
416
502
|
return false;
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
const [a, b] = await Promise.all([iter1.next(), iter2.next()]);
|
|
421
|
-
if (a.done && b.done)
|
|
422
|
-
return true;
|
|
423
|
-
if (a.done !== b.done)
|
|
424
|
-
return false;
|
|
425
|
-
if (!a.value.equals(b.value))
|
|
426
|
-
return false;
|
|
503
|
+
} }
|
|
504
|
+
checkSync() { try {
|
|
505
|
+
return fs.lstatSync(this.isAt).isFile();
|
|
427
506
|
}
|
|
428
|
-
|
|
429
|
-
export function fileSameAsSync(f1_, f2_) {
|
|
430
|
-
if (f1_.isAt === f2_.isAt)
|
|
431
|
-
return true;
|
|
432
|
-
else if (fs.statSync(f1_.isAt).size !== fs.statSync(f2_.isAt).size)
|
|
507
|
+
catch {
|
|
433
508
|
return false;
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
while (true) {
|
|
437
|
-
const a = iter1.next();
|
|
438
|
-
const b = iter2.next();
|
|
439
|
-
if (a.done && b.done)
|
|
440
|
-
return true;
|
|
441
|
-
if (a.done !== b.done)
|
|
442
|
-
return false;
|
|
443
|
-
if (!a.value.equals(b.value))
|
|
444
|
-
return false;
|
|
445
|
-
}
|
|
509
|
+
} }
|
|
510
|
+
isFile() { return true; }
|
|
446
511
|
}
|
|
447
512
|
export class Folder extends Road {
|
|
448
513
|
static async create(at_) {
|
|
@@ -454,6 +519,7 @@ export class Folder extends Road {
|
|
|
454
519
|
}
|
|
455
520
|
return new Folder(at_, false);
|
|
456
521
|
}
|
|
522
|
+
static mk = Folder.create;
|
|
457
523
|
static createSync(at_) {
|
|
458
524
|
try {
|
|
459
525
|
fs.accessSync(at_, fsc.W_OK);
|
|
@@ -463,43 +529,59 @@ export class Folder extends Road {
|
|
|
463
529
|
}
|
|
464
530
|
return new Folder(at_, false);
|
|
465
531
|
}
|
|
532
|
+
static mkSync = Folder.createSync;
|
|
466
533
|
join(...paths_) {
|
|
467
534
|
return ph.join(this.isAt, ...paths_);
|
|
468
535
|
}
|
|
469
|
-
async *it(
|
|
470
|
-
for (const
|
|
471
|
-
const road =
|
|
472
|
-
if (!
|
|
536
|
+
async *it(filter_) {
|
|
537
|
+
for (const entry of await fp.readdir(this.isAt, { withFileTypes: true })) {
|
|
538
|
+
const road = new (resolveDirent(entry))(this.join(entry.name), false);
|
|
539
|
+
if (!filter_ || filter_(road))
|
|
473
540
|
yield road;
|
|
474
541
|
}
|
|
475
542
|
}
|
|
476
|
-
*itSync(
|
|
477
|
-
for (const entry of fs.readdirSync(this.isAt)) {
|
|
478
|
-
const road =
|
|
479
|
-
if (!
|
|
543
|
+
*itSync(filter_) {
|
|
544
|
+
for (const entry of fs.readdirSync(this.isAt, { withFileTypes: true })) {
|
|
545
|
+
const road = new (resolveDirent(entry))(this.join(entry.name), false);
|
|
546
|
+
if (!filter_ || filter_(road))
|
|
480
547
|
yield road;
|
|
481
548
|
}
|
|
482
549
|
}
|
|
483
|
-
async list(
|
|
484
|
-
const entries = (await fp.readdir(this.isAt)).map(
|
|
550
|
+
async list(filter_) {
|
|
551
|
+
const entries = (await fp.readdir(this.isAt, { withFileTypes: true })).map(e => new (resolveDirent(e))(this.join(e.name), false));
|
|
485
552
|
const resolvedEntries = await Promise.all(entries);
|
|
486
|
-
if (!
|
|
553
|
+
if (!filter_)
|
|
487
554
|
return resolvedEntries;
|
|
488
|
-
return resolvedEntries.filter(entry => entry
|
|
555
|
+
return resolvedEntries.filter(entry => filter_(entry));
|
|
489
556
|
}
|
|
490
|
-
listSync(
|
|
491
|
-
const entries = fs.readdirSync(this.isAt).map(
|
|
492
|
-
if (!
|
|
557
|
+
listSync(filter_) {
|
|
558
|
+
const entries = fs.readdirSync(this.isAt, { withFileTypes: true }).map(e => new (resolveDirent(e))(this.join(e.name), false));
|
|
559
|
+
if (!filter_)
|
|
493
560
|
return entries;
|
|
494
|
-
return entries.filter(entry => entry
|
|
561
|
+
return entries.filter(entry => filter_(entry));
|
|
562
|
+
}
|
|
563
|
+
async *walk(filter_) {
|
|
564
|
+
for await (const entry of this.it()) {
|
|
565
|
+
if (!filter_ || filter_(entry))
|
|
566
|
+
yield entry;
|
|
567
|
+
if (entry.isDir())
|
|
568
|
+
yield* entry.walk(filter_);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
*walkSync(filter_) {
|
|
572
|
+
for (const entry of this.itSync()) {
|
|
573
|
+
if (!filter_ || filter_(entry))
|
|
574
|
+
yield entry;
|
|
575
|
+
if (entry.isDir())
|
|
576
|
+
yield* entry.walkSync(filter_);
|
|
577
|
+
}
|
|
495
578
|
}
|
|
496
|
-
async find(name_,
|
|
579
|
+
async find(name_, expect_) {
|
|
497
580
|
try {
|
|
498
|
-
await fp.access(this.join(name_), fs.constants.F_OK);
|
|
499
581
|
const found = await factory(this.join(name_));
|
|
500
|
-
if (!
|
|
582
|
+
if (!expect_)
|
|
501
583
|
return found;
|
|
502
|
-
if (found instanceof
|
|
584
|
+
if (found instanceof expect_)
|
|
503
585
|
return found;
|
|
504
586
|
return null;
|
|
505
587
|
}
|
|
@@ -507,16 +589,16 @@ export class Folder extends Road {
|
|
|
507
589
|
return null;
|
|
508
590
|
}
|
|
509
591
|
}
|
|
510
|
-
findSync(name_,
|
|
592
|
+
findSync(name_, expect_) {
|
|
511
593
|
try {
|
|
512
594
|
const found = factorySync(this.join(name_));
|
|
513
|
-
if (!
|
|
595
|
+
if (!expect_)
|
|
514
596
|
return found;
|
|
515
|
-
if (found instanceof
|
|
597
|
+
if (found instanceof expect_)
|
|
516
598
|
return found;
|
|
517
599
|
return null;
|
|
518
600
|
}
|
|
519
|
-
catch {
|
|
601
|
+
catch (e) {
|
|
520
602
|
return null;
|
|
521
603
|
}
|
|
522
604
|
}
|
|
@@ -530,55 +612,33 @@ export class Folder extends Road {
|
|
|
530
612
|
createable_.createSync(newPath);
|
|
531
613
|
return factorySync(newPath);
|
|
532
614
|
}
|
|
533
|
-
async
|
|
534
|
-
|
|
535
|
-
await
|
|
615
|
+
async size() {
|
|
616
|
+
let size = 0;
|
|
617
|
+
for await (const entry of this.it())
|
|
618
|
+
size += await entry.size();
|
|
619
|
+
return size;
|
|
536
620
|
}
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
621
|
+
sizeSync() {
|
|
622
|
+
let size = 0;
|
|
623
|
+
for (const entry of this.itSync())
|
|
624
|
+
size += entry.sizeSync();
|
|
625
|
+
return size;
|
|
540
626
|
}
|
|
541
|
-
async
|
|
542
|
-
|
|
543
|
-
const newPath = into_.join(this.name);
|
|
544
|
-
await fp.rename(this.isAt, newPath);
|
|
545
|
-
this.pointsTo = newPath;
|
|
627
|
+
async check() { try {
|
|
628
|
+
return (await fp.lstat(this.isAt)).isDirectory();
|
|
546
629
|
}
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
this.
|
|
552
|
-
}
|
|
553
|
-
async copy(into_) {
|
|
554
|
-
const newPath = into_.join(this.name);
|
|
555
|
-
await fp.cp(this.isAt, newPath, { recursive: true });
|
|
556
|
-
return new Folder(newPath, false);
|
|
557
|
-
}
|
|
558
|
-
copySync(into_) {
|
|
559
|
-
const newPath = into_.join(this.name);
|
|
560
|
-
fs.cpSync(this.isAt, newPath, { recursive: true });
|
|
561
|
-
return new Folder(newPath, false);
|
|
562
|
-
}
|
|
563
|
-
async rename(to_) {
|
|
564
|
-
using _ = await this.lock();
|
|
565
|
-
const newPath = this.parent().join(to_);
|
|
566
|
-
await fp.rename(this.isAt, newPath);
|
|
567
|
-
this.pointsTo = newPath;
|
|
568
|
-
}
|
|
569
|
-
renameSync(to_) {
|
|
570
|
-
using _ = this.lockSync();
|
|
571
|
-
const newPath = this.parent().join(to_);
|
|
572
|
-
fs.renameSync(this.isAt, newPath);
|
|
573
|
-
this.pointsTo = newPath;
|
|
630
|
+
catch {
|
|
631
|
+
return false;
|
|
632
|
+
} }
|
|
633
|
+
checkSync() { try {
|
|
634
|
+
return fs.lstatSync(this.isAt).isDirectory();
|
|
574
635
|
}
|
|
575
|
-
|
|
576
|
-
|
|
636
|
+
catch {
|
|
637
|
+
return false;
|
|
638
|
+
} }
|
|
577
639
|
isFolder() { return true; }
|
|
578
640
|
isDir() { return true; }
|
|
579
641
|
isDirectory() { return true; }
|
|
580
|
-
isDict() { return true; }
|
|
581
|
-
isDictionary() { return true; }
|
|
582
642
|
}
|
|
583
643
|
export function sysRoot() { return new Folder(ph.parse(process.cwd()).root, false); }
|
|
584
644
|
export function home() { return new Folder(os.homedir(), false); }
|
|
@@ -595,6 +655,7 @@ export class SymbolicLink extends Road {
|
|
|
595
655
|
}
|
|
596
656
|
return new SymbolicLink(at_, false);
|
|
597
657
|
}
|
|
658
|
+
static mk = SymbolicLink.create;
|
|
598
659
|
static createSync(at_, target_) {
|
|
599
660
|
try {
|
|
600
661
|
fs.accessSync(at_, fs.constants.F_OK);
|
|
@@ -604,6 +665,7 @@ export class SymbolicLink extends Road {
|
|
|
604
665
|
}
|
|
605
666
|
return new SymbolicLink(at_, false);
|
|
606
667
|
}
|
|
668
|
+
static mkSync = SymbolicLink.createSync;
|
|
607
669
|
async target() {
|
|
608
670
|
return factory(ph.resolve(ph.dirname(this.isAt), await fp.readlink(this.isAt)));
|
|
609
671
|
}
|
|
@@ -611,13 +673,17 @@ export class SymbolicLink extends Road {
|
|
|
611
673
|
return factorySync(ph.resolve(ph.dirname(this.isAt), fs.readlinkSync(this.isAt)));
|
|
612
674
|
}
|
|
613
675
|
async retarget(to_) {
|
|
614
|
-
await this.
|
|
615
|
-
|
|
676
|
+
using _ = await this.lock();
|
|
677
|
+
await fp.unlink(this.isAt);
|
|
678
|
+
await fp.symlink(to_.isAt, this.isAt);
|
|
616
679
|
}
|
|
617
680
|
retargetSync(to_) {
|
|
618
|
-
this.
|
|
681
|
+
using _ = this.lockSync();
|
|
682
|
+
fs.unlinkSync(this.isAt);
|
|
619
683
|
fs.symlinkSync(to_.isAt, this.isAt);
|
|
620
684
|
}
|
|
685
|
+
async size() { return (await this.lstat()).size; }
|
|
686
|
+
sizeSync() { return this.lstatSync().size; }
|
|
621
687
|
async delete() {
|
|
622
688
|
using _ = await this.lock();
|
|
623
689
|
await fp.unlink(this.isAt);
|
|
@@ -626,87 +692,136 @@ export class SymbolicLink extends Road {
|
|
|
626
692
|
using _ = this.lockSync();
|
|
627
693
|
fs.unlinkSync(this.isAt);
|
|
628
694
|
}
|
|
629
|
-
async
|
|
630
|
-
|
|
631
|
-
const newPath = into_.join(this.name);
|
|
632
|
-
await fp.rename(this.isAt, newPath);
|
|
633
|
-
this.pointsTo = newPath;
|
|
695
|
+
async check() { try {
|
|
696
|
+
return (await fp.lstat(this.isAt)).isSymbolicLink();
|
|
634
697
|
}
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
this.
|
|
640
|
-
}
|
|
641
|
-
async copy(into_) {
|
|
642
|
-
const newPath = into_.join(this.name);
|
|
643
|
-
const target = await this.target();
|
|
644
|
-
await fp.symlink(target.isAt, newPath);
|
|
645
|
-
return new SymbolicLink(newPath, false);
|
|
646
|
-
}
|
|
647
|
-
copySync(into_) {
|
|
648
|
-
const newPath = into_.join(this.name);
|
|
649
|
-
const target = this.targetSync();
|
|
650
|
-
fs.symlinkSync(target.isAt, newPath);
|
|
651
|
-
return new SymbolicLink(newPath, false);
|
|
652
|
-
}
|
|
653
|
-
async rename(to_) {
|
|
654
|
-
using _ = await this.lock();
|
|
655
|
-
const newPath = this.parent().join(to_);
|
|
656
|
-
await fp.rename(this.isAt, newPath);
|
|
657
|
-
this.pointsTo = newPath;
|
|
658
|
-
}
|
|
659
|
-
renameSync(to_) {
|
|
660
|
-
using _ = this.lockSync();
|
|
661
|
-
const newPath = this.parent().join(to_);
|
|
662
|
-
fs.renameSync(this.isAt, newPath);
|
|
663
|
-
this.pointsTo = newPath;
|
|
698
|
+
catch {
|
|
699
|
+
return false;
|
|
700
|
+
} }
|
|
701
|
+
checkSync() { try {
|
|
702
|
+
return fs.lstatSync(this.isAt).isSymbolicLink();
|
|
664
703
|
}
|
|
665
|
-
|
|
666
|
-
|
|
704
|
+
catch {
|
|
705
|
+
return false;
|
|
706
|
+
} }
|
|
667
707
|
isSymlink() { return true; }
|
|
668
708
|
isSymbolicLink() { return true; }
|
|
669
709
|
}
|
|
670
710
|
export { SymbolicLink as Symlink };
|
|
711
|
+
here().walk(r => !r.isSymlink());
|
|
671
712
|
export class UnusableRoad extends Road {
|
|
672
713
|
mutable = false; // Modification will cause system issues (e.g. deleting a device file)
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
714
|
+
async size() { return 0; }
|
|
715
|
+
sizeSync() { return 0; }
|
|
716
|
+
error() { throw new Err(`${this.constructor.name} at '${this.isAt}' is a system-level resource thus not subject to modification.`); }
|
|
717
|
+
/** @deprecated System-level resources (UnusableRoad) can't/shouldn't be locked */
|
|
718
|
+
lock() { return this.error(); }
|
|
719
|
+
/** @deprecated System-level resources (UnusableRoad) can't/shouldn't be locked */
|
|
679
720
|
lockSync() { return this.error(); }
|
|
680
|
-
|
|
721
|
+
/** @deprecated System-level resources (UnusableRoad) can't/shouldn't be deleted */
|
|
722
|
+
delete() { return this.error(); }
|
|
723
|
+
/** @deprecated System-level resources (UnusableRoad) can't/shouldn't be deleted */
|
|
681
724
|
deleteSync() { return this.error(); }
|
|
682
|
-
|
|
725
|
+
/** @deprecated System-level resources (UnusableRoad) can't/shouldn't be moved */
|
|
726
|
+
move() { return this.error(); }
|
|
727
|
+
/** @deprecated System-level resources (UnusableRoad) can't/shouldn't be moved */
|
|
683
728
|
moveSync() { return this.error(); }
|
|
684
|
-
|
|
729
|
+
/** @deprecated System-level resources (UnusableRoad) can't/shouldn't be copied */
|
|
730
|
+
copy() { return this.error(); }
|
|
731
|
+
/** @deprecated System-level resources (UnusableRoad) can't/shouldn't be copied */
|
|
685
732
|
copySync() { return this.error(); }
|
|
686
|
-
|
|
733
|
+
/** @deprecated System-level resources (UnusableRoad) can't/shouldn't be renamed */
|
|
734
|
+
rename() { return this.error(); }
|
|
735
|
+
/** @deprecated System-level resources (UnusableRoad) can't/shouldn't be renamed */
|
|
687
736
|
renameSync() { return this.error(); }
|
|
688
737
|
isUnusable() { return true; }
|
|
689
738
|
}
|
|
690
739
|
export class BlockDevice extends UnusableRoad {
|
|
691
|
-
async check() {
|
|
692
|
-
|
|
740
|
+
async check() { try {
|
|
741
|
+
return (await fp.lstat(this.isAt)).isBlockDevice();
|
|
742
|
+
}
|
|
743
|
+
catch {
|
|
744
|
+
return false;
|
|
745
|
+
} }
|
|
746
|
+
checkSync() { try {
|
|
747
|
+
return fs.lstatSync(this.isAt).isBlockDevice();
|
|
748
|
+
}
|
|
749
|
+
catch {
|
|
750
|
+
return false;
|
|
751
|
+
} }
|
|
693
752
|
isBlockDevice() { return true; }
|
|
694
753
|
}
|
|
695
754
|
export class CharacterDevice extends UnusableRoad {
|
|
696
|
-
async check() {
|
|
697
|
-
|
|
755
|
+
async check() { try {
|
|
756
|
+
return (await fp.lstat(this.isAt)).isCharacterDevice();
|
|
757
|
+
}
|
|
758
|
+
catch {
|
|
759
|
+
return false;
|
|
760
|
+
} }
|
|
761
|
+
checkSync() { try {
|
|
762
|
+
return fs.lstatSync(this.isAt).isCharacterDevice();
|
|
763
|
+
}
|
|
764
|
+
catch {
|
|
765
|
+
return false;
|
|
766
|
+
} }
|
|
698
767
|
isCharacterDevice() { return true; }
|
|
699
768
|
}
|
|
700
769
|
export class Fifo extends UnusableRoad {
|
|
701
|
-
async check() {
|
|
702
|
-
|
|
770
|
+
async check() { try {
|
|
771
|
+
return (await fp.lstat(this.isAt)).isFIFO();
|
|
772
|
+
}
|
|
773
|
+
catch {
|
|
774
|
+
return false;
|
|
775
|
+
} }
|
|
776
|
+
checkSync() { try {
|
|
777
|
+
return fs.lstatSync(this.isAt).isFIFO();
|
|
778
|
+
}
|
|
779
|
+
catch {
|
|
780
|
+
return false;
|
|
781
|
+
} }
|
|
703
782
|
isFifo() { return true; }
|
|
704
783
|
}
|
|
705
784
|
export class Socket extends UnusableRoad {
|
|
706
|
-
async check() {
|
|
707
|
-
|
|
785
|
+
async check() { try {
|
|
786
|
+
return (await fp.lstat(this.isAt)).isSocket();
|
|
787
|
+
}
|
|
788
|
+
catch {
|
|
789
|
+
return false;
|
|
790
|
+
} }
|
|
791
|
+
checkSync() { try {
|
|
792
|
+
return fs.lstatSync(this.isAt).isSocket();
|
|
793
|
+
}
|
|
794
|
+
catch {
|
|
795
|
+
return false;
|
|
796
|
+
} }
|
|
708
797
|
isSocket() { return true; }
|
|
709
798
|
}
|
|
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
|
+
}
|
|
710
825
|
let finalizer = null;
|
|
711
826
|
let toDelete = null;
|
|
712
827
|
let exitHandlerRegistered = null;
|
|
@@ -739,8 +854,22 @@ export function registerToCleanup(self_) {
|
|
|
739
854
|
toDelete.add(self_.isAt);
|
|
740
855
|
finalizer.register(self_, self_.isAt, self_);
|
|
741
856
|
}
|
|
742
|
-
export function
|
|
743
|
-
let t = createable_.
|
|
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()}`));
|
|
744
873
|
if (autoCleanup_)
|
|
745
874
|
registerToCleanup(t);
|
|
746
875
|
return Object.freeze(Object.assign(t, {
|
|
@@ -754,4 +883,3 @@ export function Temp(createable_, autoCleanup_) {
|
|
|
754
883
|
catch { } toDelete?.delete(t.isAt); finalizer?.unregister(t); }
|
|
755
884
|
}));
|
|
756
885
|
}
|
|
757
|
-
11;
|