@zenfs/core 1.11.4 → 2.0.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.
Files changed (116) hide show
  1. package/dist/backends/backend.d.ts +19 -15
  2. package/dist/backends/backend.js +31 -15
  3. package/dist/backends/cow.d.ts +20 -30
  4. package/dist/backends/cow.js +52 -142
  5. package/dist/backends/fetch.d.ts +1 -0
  6. package/dist/backends/fetch.js +3 -1
  7. package/dist/backends/index.d.ts +1 -1
  8. package/dist/backends/index.js +1 -1
  9. package/dist/backends/memory.d.ts +5 -7
  10. package/dist/backends/memory.js +2 -3
  11. package/dist/backends/passthrough.d.ts +19 -22
  12. package/dist/backends/passthrough.js +85 -160
  13. package/dist/backends/port.d.ts +207 -0
  14. package/dist/backends/port.js +297 -0
  15. package/dist/backends/single_buffer.d.ts +11 -5
  16. package/dist/backends/single_buffer.js +18 -12
  17. package/dist/backends/store/fs.d.ts +11 -27
  18. package/dist/backends/store/fs.js +67 -91
  19. package/dist/backends/store/store.d.ts +7 -12
  20. package/dist/config.d.ts +1 -10
  21. package/dist/config.js +7 -8
  22. package/dist/context.d.ts +8 -21
  23. package/dist/context.js +33 -10
  24. package/dist/index.d.ts +2 -1
  25. package/dist/index.js +2 -1
  26. package/dist/internal/contexts.d.ts +63 -0
  27. package/dist/internal/contexts.js +15 -0
  28. package/dist/internal/credentials.d.ts +2 -11
  29. package/dist/internal/credentials.js +0 -19
  30. package/dist/internal/devices.d.ts +18 -80
  31. package/dist/internal/devices.js +76 -279
  32. package/dist/internal/file_index.js +3 -3
  33. package/dist/internal/filesystem.d.ts +31 -89
  34. package/dist/internal/filesystem.js +21 -20
  35. package/dist/internal/index.d.ts +0 -1
  36. package/dist/internal/index.js +0 -1
  37. package/dist/internal/index_fs.d.ts +12 -30
  38. package/dist/internal/index_fs.js +23 -55
  39. package/dist/internal/inode.d.ts +147 -9
  40. package/dist/internal/inode.js +333 -25
  41. package/dist/internal/log.d.ts +19 -13
  42. package/dist/internal/log.js +81 -80
  43. package/dist/mixins/async.js +26 -90
  44. package/dist/mixins/mutexed.d.ts +17 -16
  45. package/dist/mixins/mutexed.js +29 -31
  46. package/dist/mixins/readonly.d.ts +7 -6
  47. package/dist/mixins/readonly.js +6 -0
  48. package/dist/mixins/sync.js +8 -8
  49. package/dist/{vfs/path.d.ts → path.d.ts} +3 -4
  50. package/dist/{vfs/path.js → path.js} +6 -9
  51. package/dist/readline.d.ts +134 -0
  52. package/dist/readline.js +623 -0
  53. package/dist/utils.d.ts +4 -35
  54. package/dist/utils.js +8 -73
  55. package/dist/vfs/acl.d.ts +42 -0
  56. package/dist/vfs/acl.js +249 -0
  57. package/dist/vfs/async.d.ts +7 -21
  58. package/dist/vfs/async.js +19 -19
  59. package/dist/vfs/config.d.ts +6 -18
  60. package/dist/vfs/config.js +8 -18
  61. package/dist/vfs/dir.d.ts +3 -3
  62. package/dist/vfs/dir.js +9 -8
  63. package/dist/vfs/file.d.ts +106 -0
  64. package/dist/vfs/file.js +235 -0
  65. package/dist/vfs/flags.d.ts +19 -0
  66. package/dist/vfs/flags.js +62 -0
  67. package/dist/vfs/index.d.ts +4 -10
  68. package/dist/vfs/index.js +4 -13
  69. package/dist/vfs/ioctl.d.ts +87 -0
  70. package/dist/vfs/ioctl.js +304 -0
  71. package/dist/vfs/promises.d.ts +78 -16
  72. package/dist/vfs/promises.js +273 -122
  73. package/dist/vfs/shared.d.ts +7 -26
  74. package/dist/vfs/shared.js +25 -53
  75. package/dist/{stats.d.ts → vfs/stats.d.ts} +14 -28
  76. package/dist/{stats.js → vfs/stats.js} +11 -66
  77. package/dist/vfs/streams.d.ts +1 -0
  78. package/dist/vfs/streams.js +24 -19
  79. package/dist/vfs/sync.d.ts +4 -3
  80. package/dist/vfs/sync.js +143 -128
  81. package/dist/vfs/watchers.d.ts +2 -2
  82. package/dist/vfs/watchers.js +6 -6
  83. package/dist/vfs/xattr.d.ts +116 -0
  84. package/dist/vfs/xattr.js +218 -0
  85. package/package.json +3 -3
  86. package/readme.md +1 -1
  87. package/tests/backend/config.worker.js +4 -1
  88. package/tests/backend/fetch.test.ts +3 -0
  89. package/tests/backend/port.test.ts +21 -35
  90. package/tests/backend/remote.worker.js +4 -1
  91. package/tests/backend/single-buffer.test.ts +24 -0
  92. package/tests/common/context.test.ts +1 -1
  93. package/tests/common/handle.test.ts +17 -12
  94. package/tests/common/path.test.ts +1 -1
  95. package/tests/common/readline.test.ts +104 -0
  96. package/tests/common.ts +4 -19
  97. package/tests/fetch/fetch.ts +1 -1
  98. package/tests/fs/links.test.ts +1 -1
  99. package/tests/fs/permissions.test.ts +7 -6
  100. package/tests/fs/readFile.test.ts +3 -3
  101. package/tests/fs/stat.test.ts +6 -6
  102. package/tests/fs/streams.test.ts +2 -11
  103. package/tests/fs/times.test.ts +1 -1
  104. package/tests/fs/xattr.test.ts +85 -0
  105. package/tests/logs.js +22 -0
  106. package/tests/setup/context.ts +1 -1
  107. package/tests/setup/index.ts +3 -3
  108. package/tests/setup/port.ts +1 -1
  109. package/dist/backends/port/fs.d.ts +0 -84
  110. package/dist/backends/port/fs.js +0 -151
  111. package/dist/backends/port/rpc.d.ts +0 -77
  112. package/dist/backends/port/rpc.js +0 -100
  113. package/dist/backends/store/simple.d.ts +0 -20
  114. package/dist/backends/store/simple.js +0 -13
  115. package/dist/internal/file.d.ts +0 -359
  116. package/dist/internal/file.js +0 -751
@@ -0,0 +1,623 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ // A cross-platform node:readline implementation
3
+ import { EventEmitter } from 'eventemitter3';
4
+ import { warn } from './internal/log.js';
5
+ export class Interface extends EventEmitter {
6
+ get cursor() {
7
+ return this._cursor;
8
+ }
9
+ constructor(input, output, completer, terminal = false) {
10
+ super();
11
+ this.input = input;
12
+ this.output = output;
13
+ this.terminal = terminal;
14
+ this.line = '';
15
+ this._cursor = 0;
16
+ this._buffer = '';
17
+ this._closed = false;
18
+ this._paused = false;
19
+ this._prompt = '';
20
+ this._history = [];
21
+ this._historyIndex = -1;
22
+ this._currentLine = '';
23
+ this._onData = (data) => {
24
+ if (this._paused || this._closed)
25
+ return;
26
+ this._buffer += typeof data === 'string' ? data : data.toString('utf8');
27
+ for (let lineEnd = this._buffer.indexOf('\n'); lineEnd >= 0; lineEnd = this._buffer.indexOf('\n')) {
28
+ let line = this._buffer.substring(0, lineEnd);
29
+ if (line.endsWith('\r')) {
30
+ line = line.substring(0, line.length - 1);
31
+ }
32
+ this._buffer = this._buffer.substring(lineEnd + 1);
33
+ this.line = line;
34
+ if (line.trim() && !line.trim().match(/^\s*$/) && this._history.at(-1) != line) {
35
+ this._history.push(line);
36
+ this._historyIndex = this._history.length;
37
+ this.emit('history', this._history);
38
+ }
39
+ this.emit('line', line);
40
+ }
41
+ };
42
+ this.input.on('data', this._onData);
43
+ this.input.on('end', this.close.bind(this));
44
+ this.input.on('close', this.close.bind(this));
45
+ }
46
+ /**
47
+ * Closes the interface and removes all event listeners
48
+ */
49
+ close() {
50
+ var _a, _b;
51
+ if (this._closed)
52
+ return;
53
+ this._closed = true;
54
+ (_b = (_a = this.input) === null || _a === void 0 ? void 0 : _a.removeAllListeners) === null || _b === void 0 ? void 0 : _b.call(_a);
55
+ if (this._buffer.length) {
56
+ const line = this._buffer;
57
+ this._buffer = '';
58
+ this.line = line;
59
+ this.emit('line', line);
60
+ }
61
+ this.emit('history', this._history);
62
+ this.emit('close');
63
+ this.removeAllListeners();
64
+ }
65
+ /**
66
+ * Pauses the input stream
67
+ */
68
+ pause() {
69
+ if (this._paused)
70
+ return this;
71
+ this._paused = true;
72
+ if ('pause' in this.input)
73
+ this.input.pause();
74
+ this.emit('pause');
75
+ return this;
76
+ }
77
+ /**
78
+ * Resumes the input stream
79
+ */
80
+ resume() {
81
+ if (!this._paused)
82
+ return this;
83
+ this._paused = false;
84
+ if ('resume' in this.input)
85
+ this.input.resume();
86
+ this.emit('resume');
87
+ return this;
88
+ }
89
+ /**
90
+ * Sets the prompt text
91
+ */
92
+ setPrompt(prompt) {
93
+ this._prompt = prompt;
94
+ }
95
+ /**
96
+ * Gets the current prompt text
97
+ */
98
+ getPrompt() {
99
+ return this._prompt;
100
+ }
101
+ /**
102
+ * Displays the prompt to the user
103
+ */
104
+ prompt(preserveCursor) {
105
+ if (!this.output)
106
+ return;
107
+ if (!preserveCursor) {
108
+ this.output.write(this._prompt);
109
+ return;
110
+ }
111
+ const { cols } = this.getCursorPos();
112
+ this.output.write(this._prompt);
113
+ this._cursor = cols;
114
+ }
115
+ /**
116
+ * Writes data to the interface and handles key events
117
+ */
118
+ write(data, key) {
119
+ if (this._closed)
120
+ return;
121
+ if (data) {
122
+ const str = typeof data === 'string' ? data : data.toString('utf8');
123
+ this._onData(str);
124
+ }
125
+ if (!key || !this.terminal)
126
+ return;
127
+ switch ((key.ctrl ? '^' : '') + key.name) {
128
+ case '^c':
129
+ this.emit('SIGINT');
130
+ break;
131
+ case '^z':
132
+ this.emit('SIGTSTP');
133
+ break;
134
+ case '^q':
135
+ this.emit('SIGCONT');
136
+ break;
137
+ case 'home':
138
+ case '^a':
139
+ if (!this.output)
140
+ return;
141
+ moveCursor(this.output, -this._cursor, 0);
142
+ this._cursor = 0;
143
+ this._cursor = 0;
144
+ break;
145
+ case '^e':
146
+ case 'end': {
147
+ if (!this.output)
148
+ return;
149
+ const dx = this.line.length - this._cursor;
150
+ if (!dx)
151
+ return;
152
+ moveCursor(this.output, dx, 0);
153
+ this._cursor = this.line.length;
154
+ this._cursor = this.line.length;
155
+ break;
156
+ }
157
+ case '^k': {
158
+ if (!this.output)
159
+ return;
160
+ if (this._cursor >= this.line.length)
161
+ return;
162
+ const newLine = this.line.slice(0, this._cursor);
163
+ clearLine(this.output, 1);
164
+ this.line = newLine;
165
+ break;
166
+ }
167
+ case '^u': {
168
+ if (!this.output || !this._cursor)
169
+ return;
170
+ const newLine = this.line.slice(this._cursor);
171
+ clearLine(this.output, 0);
172
+ moveCursor(this.output, 0, 0);
173
+ this.output.write(this._prompt + newLine);
174
+ this.line = newLine;
175
+ this._cursor = 0;
176
+ this._cursor = 0;
177
+ break;
178
+ }
179
+ case '^w': {
180
+ if (!this.output || !this._cursor)
181
+ return;
182
+ let i = this._cursor - 1;
183
+ while (i >= 0 && this.line[i] === ' ')
184
+ i--;
185
+ while (i >= 0 && this.line[i] !== ' ')
186
+ i--;
187
+ const newLine = this.line.slice(0, i + 1) + this.line.slice(this._cursor);
188
+ const newCursorPos = i + 1;
189
+ this._renderLine(newLine);
190
+ this._cursor = newCursorPos;
191
+ this._cursor = newCursorPos;
192
+ moveCursor(this.output, -newLine.length, 0);
193
+ moveCursor(this.output, newCursorPos, 0);
194
+ break;
195
+ }
196
+ case '^return':
197
+ case '^enter':
198
+ this._onData('\n');
199
+ break;
200
+ case 'return':
201
+ case 'enter':
202
+ this._onData((!data ? '' : typeof data == 'string' ? data : data.toString('utf8')) + '\n');
203
+ break;
204
+ case 'up':
205
+ case 'down': {
206
+ if (!this.output || !this._history.length)
207
+ return;
208
+ if (this._historyIndex === this._history.length) {
209
+ this._currentLine = this.line || '';
210
+ }
211
+ if (key.name == 'up' && this._historyIndex > 0) {
212
+ this._historyIndex--;
213
+ }
214
+ else if (key.name == 'down' && this._historyIndex < this._history.length - 1) {
215
+ this._historyIndex++;
216
+ }
217
+ else if (key.name == 'down' && this._historyIndex == this._history.length - 1) {
218
+ this._historyIndex = this._history.length;
219
+ this._renderLine(this._currentLine);
220
+ return;
221
+ }
222
+ else {
223
+ return;
224
+ }
225
+ const historyItem = this._history[this._historyIndex];
226
+ this._renderLine(historyItem);
227
+ break;
228
+ }
229
+ case 'left':
230
+ case 'right': {
231
+ const dx = key.name == 'left' ? -1 : 1;
232
+ if (!this.output)
233
+ return;
234
+ const newPos = Math.max(0, Math.min(this.line.length, this._cursor + dx));
235
+ if (newPos == this._cursor)
236
+ return;
237
+ moveCursor(this.output, dx, 0);
238
+ this._cursor = newPos;
239
+ this._cursor = newPos;
240
+ break;
241
+ }
242
+ case 'backspace': {
243
+ if (!this.output || !this._cursor)
244
+ return;
245
+ const newLine = this.line.slice(0, this._cursor - 1) + this.line.slice(this._cursor);
246
+ this._renderLine(newLine);
247
+ this._cursor = --this._cursor;
248
+ if (this._cursor > 0) {
249
+ moveCursor(this.output, -this._cursor, 0);
250
+ moveCursor(this.output, this._cursor, 0);
251
+ }
252
+ break;
253
+ }
254
+ case 'delete': {
255
+ if (!this.output)
256
+ return;
257
+ if (this._cursor >= this.line.length)
258
+ return;
259
+ const newLine = this.line.slice(0, this._cursor) + this.line.slice(this._cursor + 1);
260
+ clearLine(this.output, 0);
261
+ moveCursor(this.output, 0, 0);
262
+ this.output.write(this._prompt + newLine);
263
+ this.line = newLine;
264
+ moveCursor(this.output, -newLine.length, 0);
265
+ moveCursor(this.output, this._cursor, 0);
266
+ break;
267
+ }
268
+ }
269
+ }
270
+ _renderLine(text) {
271
+ if (!this.output)
272
+ return;
273
+ clearLine(this.output, 0);
274
+ moveCursor(this.output, 0, 0);
275
+ this.output.write(this._prompt + text);
276
+ this.line = text;
277
+ this._cursor = text.length;
278
+ this._cursor = text.length;
279
+ }
280
+ question(query, optionsOrCallback, maybeCallback) {
281
+ const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : maybeCallback;
282
+ if (this._closed || !this.output) {
283
+ callback('');
284
+ return;
285
+ }
286
+ this.output.write(query);
287
+ this.once('line', callback);
288
+ }
289
+ /**
290
+ * Gets the current cursor position
291
+ */
292
+ getCursorPos() {
293
+ return { rows: 0, cols: this.cursor };
294
+ }
295
+ /**
296
+ * Prepends a listener for the specified event
297
+ */
298
+ prependListener(event, listener) {
299
+ const listeners = this.listeners(event);
300
+ this.removeAllListeners(event);
301
+ this.on(event, listener);
302
+ listeners.forEach(this.on.bind(this, event));
303
+ return this;
304
+ }
305
+ /**
306
+ * Prepends a one-time listener for the specified event
307
+ */
308
+ prependOnceListener(event, listener) {
309
+ const listeners = this.listeners(event);
310
+ this.removeAllListeners(event);
311
+ this.once(event, listener);
312
+ listeners.forEach(this.on.bind(this, event));
313
+ return this;
314
+ }
315
+ /**
316
+ * Sets the maximum number of listeners
317
+ */
318
+ setMaxListeners() {
319
+ warn('Interface.prototype.setMaxListeners is not supported');
320
+ return this;
321
+ }
322
+ /**
323
+ * Gets the maximum number of listeners
324
+ */
325
+ getMaxListeners() {
326
+ warn('Interface.prototype.getMaxListeners is not supported');
327
+ return 10;
328
+ }
329
+ [Symbol.asyncIterator]() {
330
+ let done = false;
331
+ return {
332
+ next: async () => {
333
+ if (done)
334
+ return { done, value: undefined };
335
+ const { resolve, promise } = Promise.withResolvers();
336
+ this.once('line', (line) => resolve({ value: line, done: false }));
337
+ this.once('close', () => {
338
+ done = true;
339
+ resolve({ value: undefined, done });
340
+ });
341
+ return promise;
342
+ },
343
+ return: async (value) => {
344
+ if (done)
345
+ return { done, value };
346
+ done = true;
347
+ this.close();
348
+ return { done, value };
349
+ },
350
+ throw: async (error) => {
351
+ if (!done) {
352
+ done = true;
353
+ this.close();
354
+ }
355
+ throw error;
356
+ },
357
+ [Symbol.asyncIterator]() {
358
+ return this;
359
+ },
360
+ [Symbol.asyncDispose]: async () => {
361
+ if (done)
362
+ return;
363
+ done = true;
364
+ this.close();
365
+ },
366
+ };
367
+ }
368
+ async [Symbol.asyncDispose]() {
369
+ if (this._closed)
370
+ return;
371
+ const { resolve, promise } = Promise.withResolvers();
372
+ this.once('close', () => resolve());
373
+ this.close();
374
+ await promise;
375
+ }
376
+ rawListeners(event) {
377
+ return this.listeners(event);
378
+ }
379
+ }
380
+ export function createInterface(input, output, completer, terminal) {
381
+ return 'input' in input
382
+ ? new Interface(input.input, input.output, input.completer, input.terminal)
383
+ : new Interface(input, output, completer, terminal);
384
+ }
385
+ createInterface;
386
+ /**
387
+ * Clear the current line in the terminal
388
+ * @param stream The stream to clear the line on
389
+ * @param dir The direction to clear: -1 for left, 1 for right, 0 for entire line
390
+ */
391
+ export function clearLine(stream, dir) {
392
+ stream.write(dir >= 0 ? '\r\x1b[K' : '\x1b[K');
393
+ return true;
394
+ }
395
+ clearLine;
396
+ /**
397
+ * Clear the screen down from the current position
398
+ * @param stream The stream to clear the screen on
399
+ */
400
+ export function clearScreenDown(stream) {
401
+ if (!stream.write)
402
+ return false;
403
+ stream.write('\x1b[J');
404
+ return true;
405
+ }
406
+ clearScreenDown;
407
+ /**
408
+ * Move the cursor in the terminal
409
+ * @param stream The stream to move the cursor on
410
+ * @param dx The number of characters to move horizontally
411
+ * @param dy The number of lines to move vertically
412
+ */
413
+ export function moveCursor(stream, dx, dy) {
414
+ if (!stream.write)
415
+ return false;
416
+ let cmd = '';
417
+ if (dx < 0) {
418
+ cmd += `\x1b[${-dx}D`;
419
+ }
420
+ else if (dx > 0) {
421
+ cmd += `\x1b[${dx}C`;
422
+ }
423
+ if (dy < 0) {
424
+ cmd += `\x1b[${-dy}A`;
425
+ }
426
+ else if (dy > 0) {
427
+ cmd += `\x1b[${dy}B`;
428
+ }
429
+ if (cmd)
430
+ stream.write(cmd);
431
+ return true;
432
+ }
433
+ moveCursor;
434
+ const _unescaped = {
435
+ '\r': 'return',
436
+ '\n': 'enter',
437
+ '\t': 'tab',
438
+ '\b': 'backspace',
439
+ '\x7f': 'backspace',
440
+ '\x1b': 'escape',
441
+ ' ': 'space',
442
+ };
443
+ const _escaped = {
444
+ /* xterm ESC [ letter */
445
+ '[A': { name: 'up' },
446
+ '[B': { name: 'down' },
447
+ '[C': { name: 'right' },
448
+ '[D': { name: 'left' },
449
+ '[E': { name: 'clear' },
450
+ '[F': { name: 'end' },
451
+ '[H': { name: 'home' },
452
+ /* xterm/gnome ESC [ letter (with modifier) */
453
+ '[P': { name: 'f1' },
454
+ '[Q': { name: 'f2' },
455
+ '[R': { name: 'f3' },
456
+ '[S': { name: 'f4' },
457
+ /* xterm/gnome ESC O letter */
458
+ OA: { name: 'up' },
459
+ OB: { name: 'down' },
460
+ OC: { name: 'right' },
461
+ OD: { name: 'left' },
462
+ OE: { name: 'clear' },
463
+ OF: { name: 'end' },
464
+ OH: { name: 'home' },
465
+ /* xterm/gnome ESC O letter (without modifier) */
466
+ OP: { name: 'f1' },
467
+ OQ: { name: 'f2' },
468
+ OR: { name: 'f3' },
469
+ OS: { name: 'f4' },
470
+ /* xterm/rxvt ESC [ number ~ */
471
+ '[1~': { name: 'home' },
472
+ '[2~': { name: 'insert' },
473
+ '[3~': { name: 'delete' },
474
+ '[4~': { name: 'end' },
475
+ '[5~': { name: 'pageup' },
476
+ '[6~': { name: 'pagedown' },
477
+ '[7~': { name: 'home' },
478
+ '[8~': { name: 'end' },
479
+ /* xterm/rxvt ESC [ number ~ */
480
+ '[11~': { name: 'f1' },
481
+ '[12~': { name: 'f2' },
482
+ '[13~': { name: 'f3' },
483
+ '[14~': { name: 'f4' },
484
+ /* common */
485
+ '[15~': { name: 'f5' },
486
+ '[17~': { name: 'f6' },
487
+ '[18~': { name: 'f7' },
488
+ '[19~': { name: 'f8' },
489
+ '[20~': { name: 'f9' },
490
+ '[21~': { name: 'f10' },
491
+ '[23~': { name: 'f11' },
492
+ '[24~': { name: 'f12' },
493
+ /* paste bracket mode */
494
+ '[200~': { name: 'paste-start' },
495
+ '[201~': { name: 'paste-end' },
496
+ /* rxvt keys with modifiers */
497
+ '[a': { name: 'up', shift: true },
498
+ '[b': { name: 'down', shift: true },
499
+ '[c': { name: 'right', shift: true },
500
+ '[d': { name: 'left', shift: true },
501
+ '[e': { name: 'clear', shift: true },
502
+ /* from Cygwin and used in libuv */
503
+ '[[A': { name: 'f1' },
504
+ '[[B': { name: 'f2' },
505
+ '[[C': { name: 'f3' },
506
+ '[[D': { name: 'f4' },
507
+ '[[E': { name: 'f5' },
508
+ /* putty */
509
+ '[[5~': { name: 'pageup' },
510
+ '[[6~': { name: 'pagedown' },
511
+ '[2$': { name: 'insert', shift: true },
512
+ '[3$': { name: 'delete', shift: true },
513
+ '[5$': { name: 'pageup', shift: true },
514
+ '[6$': { name: 'pagedown', shift: true },
515
+ '[7$': { name: 'home', shift: true },
516
+ '[8$': { name: 'end', shift: true },
517
+ Oa: { name: 'up', ctrl: true },
518
+ Ob: { name: 'down', ctrl: true },
519
+ Oc: { name: 'right', ctrl: true },
520
+ Od: { name: 'left', ctrl: true },
521
+ Oe: { name: 'clear', ctrl: true },
522
+ '[2^': { name: 'insert', ctrl: true },
523
+ '[3^': { name: 'delete', ctrl: true },
524
+ '[5^': { name: 'pageup', ctrl: true },
525
+ '[6^': { name: 'pagedown', ctrl: true },
526
+ '[7^': { name: 'home', ctrl: true },
527
+ '[8^': { name: 'end', ctrl: true },
528
+ /* misc. */
529
+ '[Z': { name: 'tab', shift: true },
530
+ undefined: { name: 'undefined' },
531
+ };
532
+ /**
533
+ * This is an absolute monstrosity.
534
+ * It's good enough though.
535
+ */
536
+ function _parseKey(sequence) {
537
+ const key = {
538
+ sequence,
539
+ name: undefined,
540
+ ctrl: false,
541
+ meta: false,
542
+ shift: false,
543
+ };
544
+ if (sequence in _unescaped) {
545
+ key.name = _unescaped[sequence];
546
+ key.meta = sequence.startsWith('\x1b');
547
+ return key;
548
+ }
549
+ if (sequence.length == 1 && sequence.charCodeAt(0) >= 32) {
550
+ key.name = sequence.toLowerCase();
551
+ key.shift = sequence >= 'A' && sequence <= 'Z';
552
+ return key;
553
+ }
554
+ if (sequence.length == 1) {
555
+ key.ctrl = true;
556
+ key.name = String.fromCharCode(sequence.charCodeAt(0) + 64).toLowerCase();
557
+ return key;
558
+ }
559
+ if (sequence.length == 2 && sequence[0] == '\x1b' && sequence[1] >= ' ') {
560
+ key.meta = true;
561
+ key.name = sequence[1].toLowerCase();
562
+ key.shift = sequence[1] >= 'A' && sequence[1] <= 'Z';
563
+ return key;
564
+ }
565
+ if (!sequence.startsWith('\x1b'))
566
+ return key;
567
+ const rest = sequence.slice(1);
568
+ if (rest in _escaped) {
569
+ Object.assign(key, _escaped[rest]);
570
+ return key;
571
+ }
572
+ if ((!rest.startsWith('[') && !rest.startsWith('O')) || !rest.length) {
573
+ key.meta = true;
574
+ return key;
575
+ }
576
+ // Format: \x1b[Num;ModifierChar or \x1b[;ModifierChar
577
+ const match = /^\[((\d+)?(;\d+)?([~^$A-Za-z]))\]?$/.exec(rest);
578
+ if (match) {
579
+ const modifier = match[3] ? parseInt(match[3].slice(1), 10) : 1;
580
+ const baseCode = '[' + (match[2] || '') + match[4];
581
+ if (baseCode in _escaped) {
582
+ Object.assign(key, _escaped[baseCode]);
583
+ key.shift = !!(modifier & 1);
584
+ key.meta = !!(modifier & 2) || !!(modifier & 8);
585
+ key.ctrl = !!(modifier & 4);
586
+ return key;
587
+ }
588
+ }
589
+ // Check for 3-digit codes (paste mode, etc.)
590
+ const [, digits] = /^\[(\d{3})~$/.exec(rest) || [];
591
+ if (digits) {
592
+ const code = `[${digits}~`;
593
+ if (code in _escaped) {
594
+ Object.assign(key, _escaped[code]);
595
+ return key;
596
+ }
597
+ }
598
+ key.meta = true;
599
+ return key;
600
+ }
601
+ /**
602
+ * The `readline.emitKeypressEvents()` method causes the given Readable stream to begin emitting `'keypress'` events corresponding to received input.
603
+ *
604
+ * Optionally, interface specifies a `readline.Interface` instance for which autocompletion is disabled when copy-pasted input is detected.
605
+ *
606
+ * If the `stream` is a TTY, then it must be in raw mode.
607
+ *
608
+ * This is automatically called by any readline instance on its `input` if the `input` is a terminal. Closing the `readline` instance does not stop the `input` from emitting `'keypress'` events.
609
+ */
610
+ export function emitKeypressEvents(stream, readlineInterface) {
611
+ stream.on('data', (buffer) => {
612
+ const str = buffer.toString('utf8');
613
+ stream.emit('keypress', str, _parseKey(str));
614
+ });
615
+ if (!readlineInterface)
616
+ return;
617
+ stream.on('data', data => {
618
+ if (data.toString('utf8').includes('\u0003')) {
619
+ readlineInterface.emit('SIGINT');
620
+ }
621
+ });
622
+ }
623
+ emitKeypressEvents;
package/dist/utils.d.ts CHANGED
@@ -1,32 +1,11 @@
1
+ import type { UUID } from 'node:crypto';
1
2
  import type * as fs from 'node:fs';
2
- import type { ClassLike, OptionalTuple } from 'utilium';
3
+ import { type OptionalTuple } from 'utilium';
3
4
  import { ErrnoError } from './internal/error.js';
4
5
  declare global {
5
6
  function atob(data: string): string;
6
7
  function btoa(data: string): string;
7
8
  }
8
- /**
9
- * Encodes a string into a buffer
10
- * @internal
11
- */
12
- export declare function encodeRaw(input: string): Uint8Array;
13
- /**
14
- * Decodes a string from a buffer
15
- * @internal
16
- */
17
- export declare function decodeRaw(input?: Uint8Array): string;
18
- /**
19
- * Encodes a string into a buffer
20
- * @internal
21
- */
22
- export declare function encodeUTF8(input: string): Uint8Array;
23
- export { /** @deprecated @hidden */ encodeUTF8 as encode };
24
- /**
25
- * Decodes a string from a buffer
26
- * @internal
27
- */
28
- export declare function decodeUTF8(input?: Uint8Array): string;
29
- export { /** @deprecated @hidden */ decodeUTF8 as decode };
30
9
  /**
31
10
  * Decodes a directory listing
32
11
  * @hidden
@@ -69,15 +48,5 @@ export declare function normalizeOptions(options: fs.WriteFileOptions | (fs.Enco
69
48
  flag: string;
70
49
  mode: number;
71
50
  };
72
- export type Concrete<T extends ClassLike> = Pick<T, keyof T> & (new (...args: any[]) => InstanceType<T>);
73
- /**
74
- * Generate a random ino
75
- * @internal @deprecated @hidden
76
- */
77
- export declare function randomBigInt(): bigint;
78
- /**
79
- * Prevents infinite loops
80
- * @internal
81
- * @deprecated Use `canary` from Utilium
82
- */
83
- export declare function canary(path?: string, syscall?: string): () => void;
51
+ export declare function stringifyUUID(uuid: bigint): UUID;
52
+ export declare function parseUUID(uuid: UUID): bigint;