fake-node 0.2.0 → 0.3.0
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/LICENSE +21 -0
- package/README.md +3 -0
- package/lib/index.d.ts +59 -0
- package/{index.js → lib/index.js} +114 -50
- package/lib/os.d.ts +191 -0
- package/lib/os.js +271 -0
- package/lib/process.d.ts +103 -0
- package/lib/process.js +223 -0
- package/lib/querystring.d.ts +7 -0
- package/lib/querystring.js +38 -0
- package/lib/web_only_globals.json +1049 -0
- package/package.json +9 -13
- package/src/fs.ts +517 -0
- package/src/index.ts +229 -0
- package/src/os.ts +266 -0
- package/src/process.ts +263 -0
- package/src/querystring.ts +36 -0
- package/src/util.ts +408 -0
- package/index.ts +0 -148
- package/tsconfig.json +0 -10
- /package/{web_only_globals.json → src/web_only_globals.json} +0 -0
package/package.json
CHANGED
@@ -1,11 +1,16 @@
|
|
1
1
|
{
|
2
2
|
"name": "fake-node",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.3.0",
|
4
4
|
"description": "A fake version of Node that works in the browser",
|
5
5
|
"license": "MIT",
|
6
6
|
"author": "speedydelete",
|
7
7
|
"type": "commonjs",
|
8
|
-
"main": "index.js",
|
8
|
+
"main": "lib/index.js",
|
9
|
+
"types": "lib/index.d.ts",
|
10
|
+
"files": [
|
11
|
+
"/src",
|
12
|
+
"/lib"
|
13
|
+
],
|
9
14
|
"homepage": "https://github.com/speedydelete/fake-node",
|
10
15
|
"repository": {
|
11
16
|
"type": "git",
|
@@ -19,19 +24,10 @@
|
|
19
24
|
"build": "tsc"
|
20
25
|
},
|
21
26
|
"dependencies": {
|
22
|
-
"
|
23
|
-
"buffer": "^6.0.3",
|
24
|
-
"path": "^0.12.7",
|
25
|
-
"punycode": "^2.3.1",
|
26
|
-
"querystring": "^0.2.1",
|
27
|
-
"readline": "^1.3.0",
|
28
|
-
"stream": "^0.0.3",
|
29
|
-
"string_decoder": "^1.3.0",
|
30
|
-
"test": "^3.3.0",
|
31
|
-
"url": "^0.11.4",
|
32
|
-
"util": "^0.12.5"
|
27
|
+
"punycode": "^2.3.1"
|
33
28
|
},
|
34
29
|
"devDependencies": {
|
30
|
+
"@fake-node/types": "^0.4.1",
|
35
31
|
"@types/assert": "^1.5.11",
|
36
32
|
"@types/punycode": "^2.1.4",
|
37
33
|
"typescript": "^5.7.3"
|
package/src/fs.ts
ADDED
@@ -0,0 +1,517 @@
|
|
1
|
+
|
2
|
+
import * as process from './process';
|
3
|
+
import {resolve} from 'path';
|
4
|
+
import {Buffer} from 'buffer';
|
5
|
+
|
6
|
+
|
7
|
+
const F_OK = 0;
|
8
|
+
const X_OK = 1;
|
9
|
+
const W_OK = 2;
|
10
|
+
const R_OK = 4;
|
11
|
+
|
12
|
+
const COPYFILE_EXCL = 1;
|
13
|
+
const COPYFILE_FICLONE = 2;
|
14
|
+
const COPYFILE_FICLONE_FORCE = 4;
|
15
|
+
|
16
|
+
const O_RDONLY = 1;
|
17
|
+
const O_WRONLY = 2;
|
18
|
+
const O_RDWR = O_RDONLY | O_WRONLY;
|
19
|
+
const O_CREAT = 4;
|
20
|
+
const O_EXCL = 8;
|
21
|
+
const O_NOCTTY = 16;
|
22
|
+
const O_TRUNC = 32;
|
23
|
+
const O_APPEND = 64;
|
24
|
+
const O_DIRECTORY = 128;
|
25
|
+
const O_NOATIME = 256;
|
26
|
+
const O_NOFOLLOW = 512;
|
27
|
+
const O_SYNC = 1024;
|
28
|
+
const O_DSYNC = 2048;
|
29
|
+
const O_SYMLINK = 4096;
|
30
|
+
const O_DIRECT = 8192;
|
31
|
+
const O_NONBLOCK = 16384;
|
32
|
+
const UV_FS_O_FILEMAP = 32768;
|
33
|
+
|
34
|
+
const S_IMFT = 0xF000;
|
35
|
+
const S_IFREG = 0x8000;
|
36
|
+
const S_IFDIR = 0x4000;
|
37
|
+
const S_IFCHR = 0x2000;
|
38
|
+
const S_IFBLK = 0x6000;
|
39
|
+
const S_IFIFO = 0x1000;
|
40
|
+
const S_IFLNK = 0xA000;
|
41
|
+
const S_IFSOCK = 0xC000;
|
42
|
+
|
43
|
+
const S_IRWXU = 0o700;
|
44
|
+
const S_IRUSR = 0o400;
|
45
|
+
const S_IWUSR = 0o200;
|
46
|
+
const S_IXUSR = 0o100;
|
47
|
+
const S_IRWXG = 0o070;
|
48
|
+
const S_IRGRP = 0o040;
|
49
|
+
const S_IWGRP = 0o020;
|
50
|
+
const S_IXGRP = 0o010;
|
51
|
+
const S_IRWXO = 0o007;
|
52
|
+
const S_IROTH = 0o004;
|
53
|
+
const S_IWOTH = 0o002;
|
54
|
+
const S_IXOTH = 0o001;
|
55
|
+
|
56
|
+
|
57
|
+
export const constants = {F_OK, X_OK, W_OK, R_OK, COPYFILE_EXCL, COPYFILE_FICLONE, COPYFILE_FICLONE_FORCE, O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC, O_APPEND, O_DIRECTORY, O_NOATIME, O_NOFOLLOW, O_SYNC, O_DSYNC, O_SYMLINK, O_DIRECT, O_NONBLOCK, UV_FS_O_FILEMAP, S_IMFT, S_IFREG, S_IFDIR, S_IFCHR, S_IFBLK, S_IFIFO, S_IFLNK, S_IFSOCK, S_IRWXU, S_IRUSR, S_IWUSR, S_IXUSR, S_IRWXG, S_IRGRP, S_IWGRP, S_IXGRP, S_IRWXO, S_IROTH, S_IWOTH, S_IXOTH};
|
58
|
+
|
59
|
+
|
60
|
+
const encoder = new TextEncoder();
|
61
|
+
|
62
|
+
let fileDescriptors: string[] = [];
|
63
|
+
|
64
|
+
|
65
|
+
type PathArg = string | URL | Buffer | number;
|
66
|
+
|
67
|
+
function parsePathArg(arg: PathArg): string {
|
68
|
+
if (typeof arg === 'string') {
|
69
|
+
return resolve(arg);
|
70
|
+
} else if (typeof arg === 'number') {
|
71
|
+
if (fileDescriptors[arg] === null) {
|
72
|
+
throw new TypeError(`file descriptor ${arg} is closed`);
|
73
|
+
}
|
74
|
+
return fileDescriptors[arg];
|
75
|
+
} else if (arg instanceof Buffer) {
|
76
|
+
return resolve(arg.toString('utf8'));
|
77
|
+
} else if (arg instanceof URL) {
|
78
|
+
if (arg.protocol === 'file:') {
|
79
|
+
return resolve(arg.pathname);
|
80
|
+
} else {
|
81
|
+
throw new TypeError(`invalid file URL: ${arg}`);
|
82
|
+
}
|
83
|
+
} else {
|
84
|
+
throw new TypeError(`invalid path: ${arg}`);
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
const flags = {
|
89
|
+
'a': O_CREAT | O_APPEND,
|
90
|
+
'ax': O_CREAT | O_EXCL | O_APPEND,
|
91
|
+
'a+': O_RDONLY | O_CREAT | O_APPEND,
|
92
|
+
'ax+': O_RDONLY | O_CREAT | O_EXCL | O_APPEND,
|
93
|
+
'as': O_CREAT | O_APPEND | O_SYNC,
|
94
|
+
'as+': O_RDONLY | O_CREAT | O_APPEND | O_SYNC,
|
95
|
+
'r': O_RDONLY,
|
96
|
+
'rs': O_RDONLY | O_SYNC,
|
97
|
+
'r+': O_RDONLY | O_WRONLY,
|
98
|
+
'rs+': O_RDONLY | O_WRONLY | O_SYNC,
|
99
|
+
'w': O_WRONLY | O_CREAT | O_TRUNC,
|
100
|
+
'wx': O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
|
101
|
+
'w+': O_RDONLY | O_WRONLY | O_CREAT | O_TRUNC,
|
102
|
+
'wx+': O_RDONLY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
|
103
|
+
}
|
104
|
+
|
105
|
+
export type Flag = number | keyof typeof flags;
|
106
|
+
|
107
|
+
function parseFlag(flag: Flag): number {
|
108
|
+
if (typeof flag === 'string') {
|
109
|
+
return flags[flag];
|
110
|
+
} else {
|
111
|
+
return flag;
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
export type TimeArg = number | string | bigint | Date;
|
116
|
+
|
117
|
+
function parseTimeArg(time: TimeArg): bigint {
|
118
|
+
if (typeof time === 'bigint') {
|
119
|
+
return time;
|
120
|
+
} else if (typeof time === 'number') {
|
121
|
+
return BigInt(time * 1000000000);
|
122
|
+
} else if (typeof time === 'string') {
|
123
|
+
let timestamp = Date.parse(time);
|
124
|
+
if (Number.isNaN(timestamp)) {
|
125
|
+
timestamp = parseInt(time);
|
126
|
+
if (Number.isNaN(timestamp)) {
|
127
|
+
throw new TypeError(`invalid time argument ${time}`);
|
128
|
+
} else {
|
129
|
+
return BigInt(timestamp * 1000000);
|
130
|
+
}
|
131
|
+
} else {
|
132
|
+
return BigInt(timestamp * 1000000);
|
133
|
+
}
|
134
|
+
} else if (time instanceof Date) {
|
135
|
+
return BigInt(time.valueOf() * 1000000);
|
136
|
+
} else {
|
137
|
+
throw new TypeError(`invalid time value: ${time}`);
|
138
|
+
}
|
139
|
+
}
|
140
|
+
|
141
|
+
type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array;
|
142
|
+
|
143
|
+
type BufferEncoding = "ascii" | "utf8"
|
144
|
+
| "utf-8"
|
145
|
+
| "utf16le"
|
146
|
+
| "ucs2"
|
147
|
+
| "ucs-2"
|
148
|
+
| "base64"
|
149
|
+
| "latin1"
|
150
|
+
| "binary"
|
151
|
+
| "hex"
|
152
|
+
|
153
|
+
|
154
|
+
type DataArg = string | TypedArray | DataView | Iterable<any>;
|
155
|
+
|
156
|
+
function parseDataArg(data: DataArg, encoding: BufferEncoding = 'utf8'): Uint8Array {
|
157
|
+
if (typeof data === 'string') {
|
158
|
+
if (encoding === 'utf8') {
|
159
|
+
return encoder.encode(data);
|
160
|
+
} else {
|
161
|
+
// @ts-ignore
|
162
|
+
return new Uint8Array(Buffer.from(data, encoding));
|
163
|
+
}
|
164
|
+
} else if (data instanceof DataView || data instanceof Int8Array || data instanceof Uint8Array || data instanceof Uint8ClampedArray || data instanceof Int16Array || data instanceof Uint16Array || data instanceof Int32Array || data instanceof Uint32Array || data instanceof Float32Array || data instanceof Float64Array || data instanceof BigInt64Array || data instanceof BigUint64Array) {
|
165
|
+
return new Uint8Array(data.buffer);
|
166
|
+
} else if (data !== null && typeof data[Symbol.iterator] === 'function') {
|
167
|
+
return new Uint8Array(data);
|
168
|
+
} else {
|
169
|
+
throw new TypeError(`invalid binary data: ${data}`);
|
170
|
+
}
|
171
|
+
}
|
172
|
+
|
173
|
+
export type ModeArg = string | number;
|
174
|
+
|
175
|
+
const STRING_MODE_ARG_REGEX = /^([r-][w-][x-]){3}$/;
|
176
|
+
|
177
|
+
function parseModeArg(mode: ModeArg): number {
|
178
|
+
if (typeof mode === 'number') {
|
179
|
+
return mode;
|
180
|
+
} else {
|
181
|
+
if (!mode.match(STRING_MODE_ARG_REGEX)) {
|
182
|
+
throw new TypeError(`invalid chmod mode: ${mode}`)
|
183
|
+
}
|
184
|
+
// @ts-ignore
|
185
|
+
return parseInt('0b' + mode.replaceAll('-', '0').replace(/[rwx]/g, '1'));
|
186
|
+
}
|
187
|
+
}
|
188
|
+
|
189
|
+
|
190
|
+
abstract class BaseStats {
|
191
|
+
|
192
|
+
abstract mode: number | bigint;
|
193
|
+
|
194
|
+
isBlockDevice() {
|
195
|
+
return (Number(this.mode) & S_IFBLK) === S_IFBLK;
|
196
|
+
}
|
197
|
+
|
198
|
+
isCharacterDevice() {
|
199
|
+
return (Number(this.mode) & S_IFCHR) === S_IFCHR;
|
200
|
+
}
|
201
|
+
|
202
|
+
isDirectory() {
|
203
|
+
return (Number(this.mode) & S_IFDIR) === S_IFDIR;
|
204
|
+
}
|
205
|
+
|
206
|
+
isFIFO() {
|
207
|
+
return (Number(this.mode) & S_IFIFO) === S_IFIFO;
|
208
|
+
}
|
209
|
+
|
210
|
+
isFile() {
|
211
|
+
return (Number(this.mode) & S_IFREG) === S_IFREG;
|
212
|
+
}
|
213
|
+
|
214
|
+
isSocket() {
|
215
|
+
return (Number(this.mode) & S_IFSOCK) === S_IFSOCK;
|
216
|
+
}
|
217
|
+
|
218
|
+
isSymbolicLink() {
|
219
|
+
return (Number(this.mode) & S_IFLNK) === S_IFLNK;
|
220
|
+
}
|
221
|
+
|
222
|
+
}
|
223
|
+
|
224
|
+
export class Stats extends BaseStats {
|
225
|
+
|
226
|
+
dev: number;
|
227
|
+
ino: number;
|
228
|
+
mode: number;
|
229
|
+
nlink: number;
|
230
|
+
uid: number;
|
231
|
+
gid: number;
|
232
|
+
rdev: number;
|
233
|
+
size: number;
|
234
|
+
blksize: number;
|
235
|
+
blocks: number;
|
236
|
+
atimeMs: number;
|
237
|
+
mtimeMs: number;
|
238
|
+
ctimeMs: number;
|
239
|
+
birthtimeMs: number;
|
240
|
+
atime: Date;
|
241
|
+
mtime: Date;
|
242
|
+
ctime: Date;
|
243
|
+
birthtime: Date;
|
244
|
+
|
245
|
+
}
|
246
|
+
|
247
|
+
export class BigIntStats extends BaseStats {
|
248
|
+
|
249
|
+
dev: bigint;
|
250
|
+
ino: bigint;
|
251
|
+
mode: bigint;
|
252
|
+
nlink: bigint;
|
253
|
+
uid: bigint;
|
254
|
+
gid: bigint;
|
255
|
+
rdev: bigint;
|
256
|
+
size: bigint;
|
257
|
+
blksize: bigint;
|
258
|
+
blocks: bigint;
|
259
|
+
atimeMs: bigint;
|
260
|
+
mtimeMs: bigint;
|
261
|
+
ctimeMs: bigint;
|
262
|
+
birthtimeMs: bigint;
|
263
|
+
atimeNs: bigint;
|
264
|
+
mtimeNs: bigint;
|
265
|
+
ctimeNs: bigint;
|
266
|
+
birthtimeNs: bigint;
|
267
|
+
atime: Date;
|
268
|
+
mtime: Date;
|
269
|
+
ctime: Date;
|
270
|
+
birthtime: Date;
|
271
|
+
|
272
|
+
}
|
273
|
+
|
274
|
+
|
275
|
+
export class StatFs {
|
276
|
+
|
277
|
+
bavail: number;
|
278
|
+
bfree: number;
|
279
|
+
blocks: number;
|
280
|
+
bsize: number;
|
281
|
+
ffree: number;
|
282
|
+
files: number;
|
283
|
+
type: number;
|
284
|
+
|
285
|
+
}
|
286
|
+
|
287
|
+
|
288
|
+
export class BigIntStatFs {
|
289
|
+
|
290
|
+
bavail: bigint;
|
291
|
+
bfree: bigint;
|
292
|
+
blocks: bigint;
|
293
|
+
bsize: bigint;
|
294
|
+
ffree: bigint;
|
295
|
+
files: bigint;
|
296
|
+
type: bigint;
|
297
|
+
|
298
|
+
}
|
299
|
+
|
300
|
+
|
301
|
+
export interface FileParams {
|
302
|
+
mode?: number;
|
303
|
+
uid?: number;
|
304
|
+
gid?: number;
|
305
|
+
}
|
306
|
+
|
307
|
+
export class FileObject {
|
308
|
+
|
309
|
+
mode: number;
|
310
|
+
uid: number;
|
311
|
+
gid: number;
|
312
|
+
links: Directory[];
|
313
|
+
birthtime: bigint;
|
314
|
+
atime: bigint;
|
315
|
+
mtime: bigint;
|
316
|
+
ctime: bigint;
|
317
|
+
rdev: number = -1;
|
318
|
+
|
319
|
+
constructor({mode, uid, gid}: FileParams) {
|
320
|
+
this.mode = mode ?? (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
321
|
+
this.uid = uid ?? __fakeNode_process__.uid;
|
322
|
+
this.gid = gid ?? __fakeNode_process__.gid;
|
323
|
+
this.birthtime = process.hrtime.bigint();
|
324
|
+
this.atime = this.birthtime;
|
325
|
+
this.mtime = this.birthtime;
|
326
|
+
this.ctime = this.birthtime;
|
327
|
+
}
|
328
|
+
|
329
|
+
setAtime() {
|
330
|
+
this.atime = process.hrtime.bigint();
|
331
|
+
}
|
332
|
+
|
333
|
+
setMtime() {
|
334
|
+
this.mtime = process.hrtime.bigint();
|
335
|
+
}
|
336
|
+
|
337
|
+
setCtime() {
|
338
|
+
this.ctime = process.hrtime.bigint();
|
339
|
+
}
|
340
|
+
|
341
|
+
access(mode: number = F_OK): void {
|
342
|
+
const chmodInfo = (this.mode >> 3) & 0o777;
|
343
|
+
let perms: number;
|
344
|
+
if (process.getuid() === this.uid) {
|
345
|
+
perms = (chmodInfo >> 6) & 7;
|
346
|
+
} else if (process.getgid() === this.gid) {
|
347
|
+
perms = (chmodInfo >> 3) & 7;
|
348
|
+
} else {
|
349
|
+
perms = chmodInfo & 7;
|
350
|
+
}
|
351
|
+
if ((((mode & X_OK) === X_OK) && !((perms & X_OK) === X_OK)) || (((mode & W_OK) === W_OK) && !((perms & W_OK) === W_OK)) || (((mode & R_OK) === R_OK) && !((perms & R_OK) === R_OK))) {
|
352
|
+
throw new Error(`mode ${mode} and permissions ${chmodInfo} are not compatible`);
|
353
|
+
}
|
354
|
+
}
|
355
|
+
|
356
|
+
chmod(mode: string | number): void {
|
357
|
+
mode = parseModeArg(mode);
|
358
|
+
this.mode &= 0o170007;
|
359
|
+
this.mode |= mode << 3;
|
360
|
+
this.setCtime();
|
361
|
+
}
|
362
|
+
|
363
|
+
chown(uid: string | number, gid: string | number): void {
|
364
|
+
this.uid = __fakeNode__.getUIDFromUser(uid);
|
365
|
+
this.gid = __fakeNode__.getGIDFromGroup(gid);
|
366
|
+
this.setCtime();
|
367
|
+
}
|
368
|
+
|
369
|
+
cp(): FileObject {
|
370
|
+
return new FileObject({mode: this.mode, uid: this.uid, gid: this.gid});
|
371
|
+
}
|
372
|
+
|
373
|
+
cpr(): FileObject {
|
374
|
+
return this.cp();
|
375
|
+
}
|
376
|
+
|
377
|
+
get size(): number {
|
378
|
+
return -1;
|
379
|
+
}
|
380
|
+
|
381
|
+
utimes(atime: TimeArg, mtime: TimeArg) {
|
382
|
+
this.atime = parseTimeArg(atime);
|
383
|
+
this.mtime = parseTimeArg(mtime);
|
384
|
+
}
|
385
|
+
|
386
|
+
stat({bigint}: {bigint?: false}): Stats;
|
387
|
+
stat({bigint}: {bigint: true}): BigIntStats;
|
388
|
+
stat({bigint}: {bigint?: boolean}): Stats | BigIntStats {
|
389
|
+
if (bigint) {
|
390
|
+
let out = new BigIntStats();
|
391
|
+
out.dev = 0n;
|
392
|
+
out.ino = 0n;
|
393
|
+
out.mode = BigInt(this.mode);
|
394
|
+
out.nlink = BigInt(this.links.length);
|
395
|
+
out.uid = BigInt(this.uid);
|
396
|
+
out.gid = BigInt(this.gid);
|
397
|
+
out.rdev = BigInt(this.rdev);
|
398
|
+
out.size = BigInt(this.size);
|
399
|
+
out.blksize = 4096n;
|
400
|
+
out.blocks = BigInt(Math.ceil(this.size / 4096));
|
401
|
+
out.atimeMs = this.atime / 1000000n;
|
402
|
+
out.mtimeMs = this.mtime / 1000000n;
|
403
|
+
out.ctimeMs = this.ctime / 1000000n;
|
404
|
+
out.birthtimeMs = this.birthtime / 1000000n;
|
405
|
+
out.atimeNs = this.atime;
|
406
|
+
out.mtimeNs = this.mtime;
|
407
|
+
out.ctimeNs = this.ctime;
|
408
|
+
out.birthtimeNs = this.birthtime;
|
409
|
+
out.atime = new Date(Number(this.atime / 1000000n));
|
410
|
+
out.mtime = new Date(Number(this.mtime / 1000000n));
|
411
|
+
out.ctime = new Date(Number(this.ctime / 1000000n));
|
412
|
+
out.birthtime = new Date(Number(this.birthtime / 1000000n));
|
413
|
+
return out;
|
414
|
+
} else {
|
415
|
+
let out = new Stats();
|
416
|
+
out.dev = 0;
|
417
|
+
out.ino = 0;
|
418
|
+
out.mode = this.mode;
|
419
|
+
out.nlink = this.links.length;
|
420
|
+
out.uid = this.uid;
|
421
|
+
out.gid = this.gid;
|
422
|
+
out.rdev = this.rdev;
|
423
|
+
out.size = this.size;
|
424
|
+
out.blksize = 4096;
|
425
|
+
out.blocks = Math.ceil(this.size / 4096);
|
426
|
+
out.atimeMs = Number(this.atime / 1000000n);
|
427
|
+
out.mtimeMs = Number(this.mtime / 1000000n);
|
428
|
+
out.ctimeMs = Number(this.ctime / 1000000n);
|
429
|
+
out.birthtimeMs = Number(this.birthtime / 1000000n);
|
430
|
+
out.atime = new Date(Number(this.atime / 1000000n));
|
431
|
+
out.mtime = new Date(Number(this.mtime / 1000000n));
|
432
|
+
out.ctime = new Date(Number(this.ctime / 1000000n));
|
433
|
+
out.birthtime = new Date(Number(this.birthtime / 1000000n));
|
434
|
+
return out;
|
435
|
+
}
|
436
|
+
}
|
437
|
+
|
438
|
+
}
|
439
|
+
|
440
|
+
|
441
|
+
export class RegularFile extends FileObject {
|
442
|
+
|
443
|
+
data: Uint8Array;
|
444
|
+
|
445
|
+
constructor(data: DataArg, {mode = 0o6440, encoding, ...params}: FileParams & {encoding?: string}) {
|
446
|
+
super({mode: mode | S_IFREG, ...params});
|
447
|
+
this.write(data);
|
448
|
+
}
|
449
|
+
|
450
|
+
cp(): RegularFile {
|
451
|
+
return new RegularFile(new Uint8Array(this.data), {mode: this.mode, uid: this.uid, gid: this.gid});
|
452
|
+
}
|
453
|
+
|
454
|
+
read(encoding: BufferEncoding, start: number, length: number): string;
|
455
|
+
read(encoding: 'uint8array', start: number, length: number): Uint8Array;
|
456
|
+
read(encoding: 'buffer', start: number, length: number): Buffer;
|
457
|
+
read(encoding: BufferEncoding | 'uint8array' | 'buffer' = 'utf8', start: number = 0, length: number = -1): string | Uint8Array | Buffer {
|
458
|
+
if (encoding === 'uint8array') {
|
459
|
+
return this.data;
|
460
|
+
} else if (encoding === 'buffer') {
|
461
|
+
return Buffer.from(this.data);
|
462
|
+
} else {
|
463
|
+
return (new TextDecoder(encoding)).decode(this.data);
|
464
|
+
}
|
465
|
+
}
|
466
|
+
|
467
|
+
write(data: string, position?: number, encoding?: BufferEncoding): void;
|
468
|
+
write(data: TypedArray | DataView | Iterable<any>, offset?: number, length?: number): void;
|
469
|
+
write(data: DataArg, position?: number, encoding_or_length?: number | BufferEncoding): void {
|
470
|
+
const encoding = typeof encoding_or_length === 'string' ? encoding_or_length : 'utf8';
|
471
|
+
const length = typeof encoding_or_length === 'number' ? encoding_or_length : -1;
|
472
|
+
const array = parseDataArg(data, encoding);
|
473
|
+
if (position === 0 && length === -1) {
|
474
|
+
this.data = array;
|
475
|
+
} else if (length === -1) {
|
476
|
+
this.data.set(array, position);
|
477
|
+
} else {
|
478
|
+
this.data.set(array.slice(0, length), position);
|
479
|
+
}
|
480
|
+
}
|
481
|
+
|
482
|
+
}
|
483
|
+
|
484
|
+
|
485
|
+
export class Directory extends FileObject {
|
486
|
+
|
487
|
+
files: Map<string, FileObject>;
|
488
|
+
|
489
|
+
constructor(files: Map<string, FileObject>, {mode, ...params}: FileParams);
|
490
|
+
constructor(files: {[key: string]: FileObject}, {mode, ...params}: FileParams);
|
491
|
+
constructor(files: MapIterator<[string, FileObject]>, {mode, ...params}: FileParams);
|
492
|
+
constructor(files: Map<string, FileObject> | {[key: string]: FileObject} | MapIterator<[string, FileObject]> = new Map(), {mode = 0o6440, ...params}: FileParams) {
|
493
|
+
super({mode: mode | S_IFDIR, ...params});
|
494
|
+
if (files instanceof Map) {
|
495
|
+
this.files = files;
|
496
|
+
} else {
|
497
|
+
this.files = new Map(Object.entries(files));
|
498
|
+
}
|
499
|
+
}
|
500
|
+
|
501
|
+
get(path: PathArg): FileObject {
|
502
|
+
const file = this.files.get(parsePathArg(path));
|
503
|
+
if (file === undefined) {
|
504
|
+
throw new TypeError(`file ${path} does not exist`);
|
505
|
+
}
|
506
|
+
return file;
|
507
|
+
}
|
508
|
+
|
509
|
+
cp(): Directory {
|
510
|
+
return new Directory(this.files.entries(), {mode: this.mode, uid: this.uid, gid: this.gid});
|
511
|
+
}
|
512
|
+
|
513
|
+
cpr(): Directory {
|
514
|
+
return new Directory(new Map(Array.from(this.files.entries()).map(([name, file]) => [name, file.cpr()])), {mode: this.mode, uid: this.uid, gid: this.gid});
|
515
|
+
}
|
516
|
+
|
517
|
+
}
|