readline-pager 0.2.6 → 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/README.md +65 -40
- package/dist/main.cjs +407 -148
- package/dist/main.d.cts +3 -5
- package/dist/main.d.mts +3 -5
- package/dist/main.mjs +402 -147
- package/dist/worker.cjs +15 -13
- package/dist/worker.mjs +15 -13
- package/package.json +15 -7
- package/prebuilds/linux-x64/readline-pager.node +0 -0
package/dist/main.cjs
CHANGED
|
@@ -1,63 +1,189 @@
|
|
|
1
|
-
Object.defineProperties(exports, {
|
|
1
|
+
Object.defineProperties(exports, {
|
|
2
|
+
__esModule: { value: true },
|
|
3
|
+
[Symbol.toStringTag]: { value: "Module" }
|
|
4
|
+
});
|
|
5
|
+
let node_fs = require("node:fs");
|
|
2
6
|
let node_fs_promises = require("node:fs/promises");
|
|
3
7
|
let node_worker_threads = require("node:worker_threads");
|
|
4
|
-
|
|
5
8
|
//#region src/queue.ts
|
|
6
|
-
function
|
|
7
|
-
|
|
8
|
-
let
|
|
9
|
+
function createRingBuffer(capacity) {
|
|
10
|
+
if (!Number.isFinite(capacity) || capacity <= 0) throw new RangeError("capacity must be a positive number");
|
|
11
|
+
let buf = new Array(capacity);
|
|
12
|
+
let head = 0;
|
|
13
|
+
let tail = 0;
|
|
14
|
+
let count = 0;
|
|
15
|
+
let consumerWaiter = null;
|
|
16
|
+
let producerWaiter = null;
|
|
17
|
+
function push(item) {
|
|
18
|
+
if (count === buf.length) {
|
|
19
|
+
const newCap = buf.length * 2;
|
|
20
|
+
const newBuf = new Array(newCap);
|
|
21
|
+
for (let i = 0; i < count; i++) newBuf[i] = buf[(head + i) % buf.length];
|
|
22
|
+
buf = newBuf;
|
|
23
|
+
head = 0;
|
|
24
|
+
tail = count;
|
|
25
|
+
}
|
|
26
|
+
buf[tail] = item;
|
|
27
|
+
tail++;
|
|
28
|
+
if (tail === buf.length) tail = 0;
|
|
29
|
+
count++;
|
|
30
|
+
if (consumerWaiter) {
|
|
31
|
+
const w = consumerWaiter;
|
|
32
|
+
consumerWaiter = null;
|
|
33
|
+
w();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function shiftSync() {
|
|
37
|
+
if (count === 0) return null;
|
|
38
|
+
const v = buf[head];
|
|
39
|
+
buf[head] = void 0;
|
|
40
|
+
head++;
|
|
41
|
+
if (head === buf.length) head = 0;
|
|
42
|
+
count--;
|
|
43
|
+
if (producerWaiter) {
|
|
44
|
+
const w = producerWaiter;
|
|
45
|
+
producerWaiter = null;
|
|
46
|
+
w();
|
|
47
|
+
}
|
|
48
|
+
return v;
|
|
49
|
+
}
|
|
50
|
+
async function shift(done = false) {
|
|
51
|
+
if (count) return shiftSync();
|
|
52
|
+
if (done) return null;
|
|
53
|
+
await new Promise((r) => {
|
|
54
|
+
consumerWaiter = r;
|
|
55
|
+
});
|
|
56
|
+
if (count) return shiftSync();
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
function wake() {
|
|
60
|
+
if (consumerWaiter) {
|
|
61
|
+
const w = consumerWaiter;
|
|
62
|
+
consumerWaiter = null;
|
|
63
|
+
w();
|
|
64
|
+
}
|
|
65
|
+
if (producerWaiter) {
|
|
66
|
+
const w = producerWaiter;
|
|
67
|
+
producerWaiter = null;
|
|
68
|
+
w();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function clear() {
|
|
72
|
+
for (let i = 0; i < buf.length; i++) buf[i] = void 0;
|
|
73
|
+
head = 0;
|
|
74
|
+
tail = 0;
|
|
75
|
+
count = 0;
|
|
76
|
+
wake();
|
|
77
|
+
}
|
|
9
78
|
return {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
resolver?.();
|
|
18
|
-
resolver = null;
|
|
79
|
+
push,
|
|
80
|
+
shift,
|
|
81
|
+
shiftSync,
|
|
82
|
+
wake,
|
|
83
|
+
clear,
|
|
84
|
+
get count() {
|
|
85
|
+
return count;
|
|
19
86
|
},
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if (done()) return null;
|
|
23
|
-
await new Promise((r) => resolver = r);
|
|
24
|
-
if (queue.length) return queue.shift();
|
|
25
|
-
if (done()) return null;
|
|
26
|
-
return null;
|
|
87
|
+
get capacity() {
|
|
88
|
+
return buf.length;
|
|
27
89
|
}
|
|
28
90
|
};
|
|
29
91
|
}
|
|
30
|
-
|
|
31
92
|
//#endregion
|
|
32
93
|
//#region src/reader/backward.reader.ts
|
|
33
94
|
function createBackwardReader(filepath, options) {
|
|
34
95
|
const { chunkSize, pageSize, delimiter, prefetch } = options;
|
|
35
|
-
const pageQueue =
|
|
96
|
+
const pageQueue = createRingBuffer(Math.max(2, prefetch + 1));
|
|
97
|
+
const local = [];
|
|
36
98
|
let fd = null;
|
|
99
|
+
let fdSync = null;
|
|
37
100
|
let pos = 0;
|
|
38
101
|
let buffer = "";
|
|
39
102
|
let done = false;
|
|
40
103
|
let closed = false;
|
|
41
|
-
let
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
pos = (await fd.stat()).size;
|
|
49
|
-
if (pos === 0) done = true;
|
|
104
|
+
let startsWithDelimiter = false;
|
|
105
|
+
fdSync = (0, node_fs.openSync)(filepath, "r");
|
|
106
|
+
pos = (0, node_fs.statSync)(filepath).size;
|
|
107
|
+
if (pos === 0) {
|
|
108
|
+
pageQueue.push([buffer]);
|
|
109
|
+
done = true;
|
|
110
|
+
pageQueue.wake();
|
|
50
111
|
}
|
|
51
|
-
async
|
|
112
|
+
(async () => {
|
|
113
|
+
try {
|
|
114
|
+
fd = await (0, node_fs_promises.open)(filepath, "r");
|
|
115
|
+
pos = (await fd.stat()).size;
|
|
116
|
+
if (pos === 0) {
|
|
117
|
+
if (!done) {
|
|
118
|
+
pageQueue.push([buffer]);
|
|
119
|
+
done = true;
|
|
120
|
+
}
|
|
121
|
+
if (fd) {
|
|
122
|
+
await fd.close();
|
|
123
|
+
fd = null;
|
|
124
|
+
}
|
|
125
|
+
pageQueue.wake();
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
while (!done && !closed) {
|
|
129
|
+
while (pageQueue.count < prefetch && pos > 0 && !closed) {
|
|
130
|
+
const readSize = Math.min(chunkSize, pos);
|
|
131
|
+
pos -= readSize;
|
|
132
|
+
const buf = Buffer.allocUnsafe(readSize);
|
|
133
|
+
await fd.read(buf, 0, readSize, pos);
|
|
134
|
+
buffer = buf.toString("utf8") + buffer;
|
|
135
|
+
if (pos === 0 && buffer.startsWith(delimiter)) startsWithDelimiter = true;
|
|
136
|
+
let idx;
|
|
137
|
+
while ((idx = buffer.lastIndexOf(delimiter)) !== -1) {
|
|
138
|
+
const line = buffer.slice(idx + delimiter.length);
|
|
139
|
+
buffer = buffer.slice(0, idx);
|
|
140
|
+
local.push(line);
|
|
141
|
+
while (local.length >= pageSize) {
|
|
142
|
+
const page = local.splice(0, pageSize);
|
|
143
|
+
pageQueue.push(page);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (pos === 0 && !done) {
|
|
148
|
+
if (buffer.length > 0) local.push(buffer);
|
|
149
|
+
else if (startsWithDelimiter) local.push("");
|
|
150
|
+
buffer = "";
|
|
151
|
+
while (local.length > 0 && !closed) {
|
|
152
|
+
const page = local.slice(local.length - Math.min(pageSize, local.length));
|
|
153
|
+
local.length -= page.length;
|
|
154
|
+
pageQueue.push(page);
|
|
155
|
+
}
|
|
156
|
+
done = true;
|
|
157
|
+
if (fd) {
|
|
158
|
+
await fd.close();
|
|
159
|
+
fd = null;
|
|
160
|
+
}
|
|
161
|
+
pageQueue.wake();
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
if (!done && !closed) await new Promise((r) => setImmediate(r));
|
|
165
|
+
}
|
|
166
|
+
} catch {
|
|
167
|
+
done = true;
|
|
168
|
+
pageQueue.wake();
|
|
169
|
+
try {
|
|
170
|
+
if (fd) {
|
|
171
|
+
await fd.close();
|
|
172
|
+
fd = null;
|
|
173
|
+
}
|
|
174
|
+
} catch {}
|
|
175
|
+
}
|
|
176
|
+
})();
|
|
177
|
+
function fillSync() {
|
|
52
178
|
if (done || closed) return;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
while (pageQueue.queue.length < prefetch && pos > 0) {
|
|
179
|
+
if (fdSync === null) return;
|
|
180
|
+
while (pageQueue.count < prefetch && pos > 0 && !closed) {
|
|
56
181
|
const readSize = Math.min(chunkSize, pos);
|
|
57
182
|
pos -= readSize;
|
|
58
183
|
const buf = Buffer.allocUnsafe(readSize);
|
|
59
|
-
|
|
60
|
-
buffer
|
|
184
|
+
(0, node_fs.readSync)(fdSync, buf, 0, readSize, pos);
|
|
185
|
+
buffer = buf.toString("utf8") + buffer;
|
|
186
|
+
if (pos === 0 && buffer.startsWith(delimiter)) startsWithDelimiter = true;
|
|
61
187
|
let idx;
|
|
62
188
|
while ((idx = buffer.lastIndexOf(delimiter)) !== -1) {
|
|
63
189
|
const line = buffer.slice(idx + delimiter.length);
|
|
@@ -69,90 +195,178 @@ function createBackwardReader(filepath, options) {
|
|
|
69
195
|
}
|
|
70
196
|
}
|
|
71
197
|
}
|
|
72
|
-
if (pos === 0) {
|
|
73
|
-
local.push(buffer);
|
|
198
|
+
if (pos === 0 && !done) {
|
|
199
|
+
if (buffer.length > 0) local.push(buffer);
|
|
200
|
+
else if (startsWithDelimiter) local.push("");
|
|
74
201
|
buffer = "";
|
|
75
202
|
while (local.length > 0) {
|
|
76
|
-
const
|
|
77
|
-
|
|
203
|
+
const page = local.slice(local.length - Math.min(pageSize, local.length));
|
|
204
|
+
local.length -= page.length;
|
|
78
205
|
pageQueue.push(page);
|
|
79
206
|
}
|
|
80
207
|
done = true;
|
|
81
|
-
if (
|
|
82
|
-
|
|
83
|
-
|
|
208
|
+
if (fdSync !== null) {
|
|
209
|
+
(0, node_fs.closeSync)(fdSync);
|
|
210
|
+
fdSync = null;
|
|
84
211
|
}
|
|
212
|
+
pageQueue.wake();
|
|
85
213
|
}
|
|
86
214
|
}
|
|
87
215
|
async function next() {
|
|
88
216
|
if (closed) return null;
|
|
89
|
-
await
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return page;
|
|
217
|
+
return await pageQueue.shift(done);
|
|
218
|
+
}
|
|
219
|
+
function nextSync() {
|
|
220
|
+
if (closed) return null;
|
|
221
|
+
fillSync();
|
|
222
|
+
return pageQueue.shiftSync();
|
|
96
223
|
}
|
|
97
224
|
async function close() {
|
|
98
225
|
closed = true;
|
|
99
226
|
done = true;
|
|
100
|
-
pageQueue.
|
|
101
|
-
if (fd)
|
|
227
|
+
pageQueue.clear();
|
|
228
|
+
if (fd) {
|
|
229
|
+
try {
|
|
230
|
+
await fd.close();
|
|
231
|
+
} catch {}
|
|
232
|
+
fd = null;
|
|
233
|
+
}
|
|
234
|
+
if (fdSync !== null) {
|
|
235
|
+
try {
|
|
236
|
+
(0, node_fs.closeSync)(fdSync);
|
|
237
|
+
} catch {}
|
|
238
|
+
fdSync = null;
|
|
239
|
+
}
|
|
102
240
|
}
|
|
103
241
|
return {
|
|
104
242
|
next,
|
|
243
|
+
nextSync,
|
|
105
244
|
close,
|
|
106
|
-
get lineCount() {
|
|
107
|
-
return emittedCount;
|
|
108
|
-
},
|
|
109
|
-
get firstLine() {
|
|
110
|
-
return firstLine;
|
|
111
|
-
},
|
|
112
|
-
get lastLine() {
|
|
113
|
-
return lastLine;
|
|
114
|
-
},
|
|
115
245
|
async *[Symbol.asyncIterator]() {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
246
|
+
try {
|
|
247
|
+
while (true) {
|
|
248
|
+
const p = await next();
|
|
249
|
+
if (!p) break;
|
|
250
|
+
yield p;
|
|
251
|
+
}
|
|
252
|
+
} finally {
|
|
253
|
+
await close();
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
*[Symbol.iterator]() {
|
|
257
|
+
try {
|
|
258
|
+
while (true) {
|
|
259
|
+
const p = nextSync();
|
|
260
|
+
if (!p) break;
|
|
261
|
+
yield p;
|
|
262
|
+
}
|
|
263
|
+
} finally {
|
|
264
|
+
closed = true;
|
|
265
|
+
done = true;
|
|
266
|
+
pageQueue.clear();
|
|
267
|
+
try {
|
|
268
|
+
if (fdSync) (0, node_fs.closeSync)(fdSync);
|
|
269
|
+
} catch {}
|
|
270
|
+
fdSync = null;
|
|
271
|
+
try {
|
|
272
|
+
if (fd?.fd) (0, node_fs.closeSync)(fd.fd);
|
|
273
|
+
} catch {}
|
|
274
|
+
fd = null;
|
|
120
275
|
}
|
|
121
276
|
}
|
|
122
277
|
};
|
|
123
278
|
}
|
|
124
|
-
|
|
125
279
|
//#endregion
|
|
126
280
|
//#region src/reader/forward.reader.ts
|
|
127
281
|
function createForwardReader(filepath, options) {
|
|
128
282
|
const { chunkSize, pageSize, delimiter, prefetch } = options;
|
|
129
|
-
const pageQueue =
|
|
283
|
+
const pageQueue = createRingBuffer(Math.max(2, prefetch + 1));
|
|
284
|
+
const local = [];
|
|
130
285
|
let fd = null;
|
|
286
|
+
let fdSync = null;
|
|
131
287
|
let pos = 0;
|
|
132
288
|
let size = 0;
|
|
133
289
|
let buffer = "";
|
|
134
290
|
let done = false;
|
|
135
291
|
let closed = false;
|
|
136
|
-
let
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
size = (await fd.stat()).size;
|
|
144
|
-
if (size === 0) done = true;
|
|
292
|
+
let flushed = false;
|
|
293
|
+
fdSync = (0, node_fs.openSync)(filepath, "r");
|
|
294
|
+
size = (0, node_fs.statSync)(filepath).size;
|
|
295
|
+
if (size === 0) {
|
|
296
|
+
pageQueue.push([buffer]);
|
|
297
|
+
done = true;
|
|
298
|
+
pageQueue.wake();
|
|
145
299
|
}
|
|
146
|
-
async
|
|
300
|
+
(async () => {
|
|
301
|
+
try {
|
|
302
|
+
fd = await (0, node_fs_promises.open)(filepath, "r");
|
|
303
|
+
size = (await fd.stat()).size;
|
|
304
|
+
if (size === 0) {
|
|
305
|
+
if (!done) {
|
|
306
|
+
pageQueue.push([buffer]);
|
|
307
|
+
done = true;
|
|
308
|
+
}
|
|
309
|
+
if (fd) {
|
|
310
|
+
await fd.close();
|
|
311
|
+
fd = null;
|
|
312
|
+
}
|
|
313
|
+
pageQueue.wake();
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
while (!done && !closed) {
|
|
317
|
+
while (pageQueue.count < prefetch && pos < size && !closed) {
|
|
318
|
+
const readSize = Math.min(chunkSize, size - pos);
|
|
319
|
+
const buf = Buffer.allocUnsafe(readSize);
|
|
320
|
+
const { bytesRead } = await fd.read(buf, 0, readSize, pos);
|
|
321
|
+
pos += bytesRead;
|
|
322
|
+
buffer = buffer + buf.toString("utf8", 0, bytesRead);
|
|
323
|
+
let idx;
|
|
324
|
+
while ((idx = buffer.indexOf(delimiter)) !== -1) {
|
|
325
|
+
const line = buffer.slice(0, idx);
|
|
326
|
+
buffer = buffer.slice(idx + delimiter.length);
|
|
327
|
+
local.push(line);
|
|
328
|
+
while (local.length >= pageSize) pageQueue.push(local.splice(0, pageSize));
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
if (pos >= size && !flushed) {
|
|
332
|
+
flushed = true;
|
|
333
|
+
local.push(buffer.length > 0 ? buffer : "");
|
|
334
|
+
buffer = "";
|
|
335
|
+
while (local.length > 0 && !closed) {
|
|
336
|
+
const page = local.slice(0, pageSize);
|
|
337
|
+
local.length -= page.length;
|
|
338
|
+
pageQueue.push(page);
|
|
339
|
+
}
|
|
340
|
+
done = true;
|
|
341
|
+
if (fd) {
|
|
342
|
+
await fd.close();
|
|
343
|
+
fd = null;
|
|
344
|
+
}
|
|
345
|
+
pageQueue.wake();
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
if (!done && !closed) await new Promise((r) => setImmediate(r));
|
|
349
|
+
}
|
|
350
|
+
} catch {
|
|
351
|
+
done = true;
|
|
352
|
+
pageQueue.wake();
|
|
353
|
+
try {
|
|
354
|
+
if (fd) {
|
|
355
|
+
await fd.close();
|
|
356
|
+
fd = null;
|
|
357
|
+
}
|
|
358
|
+
} catch {}
|
|
359
|
+
}
|
|
360
|
+
})();
|
|
361
|
+
function fillSync() {
|
|
147
362
|
if (done || closed) return;
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
while (pageQueue.queue.length < prefetch && pos < size) {
|
|
363
|
+
if (fdSync === null) return;
|
|
364
|
+
while (pageQueue.count < prefetch && pos < size && !closed) {
|
|
151
365
|
const readSize = Math.min(chunkSize, size - pos);
|
|
152
366
|
const buf = Buffer.allocUnsafe(readSize);
|
|
153
|
-
const
|
|
367
|
+
const bytesRead = (0, node_fs.readSync)(fdSync, buf, 0, readSize, pos);
|
|
154
368
|
pos += bytesRead;
|
|
155
|
-
buffer
|
|
369
|
+
buffer = buffer + buf.toString("utf8", 0, bytesRead);
|
|
156
370
|
let idx;
|
|
157
371
|
while ((idx = buffer.indexOf(delimiter)) !== -1) {
|
|
158
372
|
const line = buffer.slice(0, idx);
|
|
@@ -161,73 +375,102 @@ function createForwardReader(filepath, options) {
|
|
|
161
375
|
while (local.length >= pageSize) pageQueue.push(local.splice(0, pageSize));
|
|
162
376
|
}
|
|
163
377
|
}
|
|
164
|
-
if (pos >= size) {
|
|
165
|
-
|
|
166
|
-
|
|
378
|
+
if (pos >= size && !flushed) {
|
|
379
|
+
flushed = true;
|
|
380
|
+
local.push(buffer.length > 0 ? buffer : "");
|
|
167
381
|
buffer = "";
|
|
168
|
-
while (local.length > 0)
|
|
382
|
+
while (local.length > 0) {
|
|
383
|
+
const page = local.slice(0, pageSize);
|
|
384
|
+
local.length -= page.length;
|
|
385
|
+
pageQueue.push(page);
|
|
386
|
+
}
|
|
169
387
|
done = true;
|
|
170
|
-
if (
|
|
171
|
-
|
|
172
|
-
|
|
388
|
+
if (fdSync !== null) {
|
|
389
|
+
(0, node_fs.closeSync)(fdSync);
|
|
390
|
+
fdSync = null;
|
|
173
391
|
}
|
|
392
|
+
pageQueue.wake();
|
|
174
393
|
}
|
|
175
394
|
}
|
|
176
395
|
async function next() {
|
|
177
396
|
if (closed) return null;
|
|
178
|
-
await
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
return page;
|
|
397
|
+
return await pageQueue.shift(done);
|
|
398
|
+
}
|
|
399
|
+
function nextSync() {
|
|
400
|
+
if (closed) return null;
|
|
401
|
+
fillSync();
|
|
402
|
+
return pageQueue.shiftSync();
|
|
185
403
|
}
|
|
186
404
|
async function close() {
|
|
187
405
|
closed = true;
|
|
188
406
|
done = true;
|
|
189
|
-
pageQueue.
|
|
190
|
-
if (fd)
|
|
407
|
+
pageQueue.clear();
|
|
408
|
+
if (fd) {
|
|
409
|
+
try {
|
|
410
|
+
await fd.close();
|
|
411
|
+
} catch {}
|
|
412
|
+
fd = null;
|
|
413
|
+
}
|
|
414
|
+
if (fdSync !== null) {
|
|
415
|
+
try {
|
|
416
|
+
(0, node_fs.closeSync)(fdSync);
|
|
417
|
+
} catch {}
|
|
418
|
+
fdSync = null;
|
|
419
|
+
}
|
|
191
420
|
}
|
|
192
421
|
return {
|
|
193
422
|
next,
|
|
423
|
+
nextSync,
|
|
194
424
|
close,
|
|
195
|
-
get lineCount() {
|
|
196
|
-
return emittedCount;
|
|
197
|
-
},
|
|
198
|
-
get firstLine() {
|
|
199
|
-
return firstLine;
|
|
200
|
-
},
|
|
201
|
-
get lastLine() {
|
|
202
|
-
return lastLine;
|
|
203
|
-
},
|
|
204
425
|
async *[Symbol.asyncIterator]() {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
426
|
+
try {
|
|
427
|
+
while (true) {
|
|
428
|
+
const p = await next();
|
|
429
|
+
if (!p) break;
|
|
430
|
+
yield p;
|
|
431
|
+
}
|
|
432
|
+
} finally {
|
|
433
|
+
await close();
|
|
434
|
+
}
|
|
435
|
+
},
|
|
436
|
+
*[Symbol.iterator]() {
|
|
437
|
+
try {
|
|
438
|
+
while (true) {
|
|
439
|
+
const p = nextSync();
|
|
440
|
+
if (!p) break;
|
|
441
|
+
yield p;
|
|
442
|
+
}
|
|
443
|
+
} finally {
|
|
444
|
+
closed = true;
|
|
445
|
+
done = true;
|
|
446
|
+
pageQueue.clear();
|
|
447
|
+
try {
|
|
448
|
+
if (fdSync !== null) (0, node_fs.closeSync)(fdSync);
|
|
449
|
+
} catch {}
|
|
450
|
+
fdSync = null;
|
|
451
|
+
try {
|
|
452
|
+
if (fd?.fd) (0, node_fs.closeSync)(fd.fd);
|
|
453
|
+
} catch {}
|
|
454
|
+
fd = null;
|
|
209
455
|
}
|
|
210
456
|
}
|
|
211
457
|
};
|
|
212
458
|
}
|
|
213
|
-
|
|
214
459
|
//#endregion
|
|
215
460
|
//#region src/reader/worker.reader.ts
|
|
216
|
-
const workerFile =
|
|
461
|
+
const workerFile = new URL("./worker.mjs", require("url").pathToFileURL(__filename).href);
|
|
217
462
|
function createWorkerReader(filepath, options) {
|
|
218
463
|
const { chunkSize, pageSize, delimiter, prefetch } = options;
|
|
464
|
+
const pageQueue = createRingBuffer(Math.max(2, prefetch + 1));
|
|
465
|
+
let done = false;
|
|
466
|
+
let closed = false;
|
|
219
467
|
const worker = new node_worker_threads.Worker(new URL(workerFile, require("url").pathToFileURL(__filename).href), { workerData: {
|
|
220
468
|
filepath,
|
|
221
469
|
chunkSize,
|
|
222
470
|
pageSize,
|
|
223
|
-
delimiter
|
|
471
|
+
delimiter,
|
|
472
|
+
prefetch
|
|
224
473
|
} });
|
|
225
|
-
const pageQueue = createPageQueue();
|
|
226
|
-
let done = false;
|
|
227
|
-
let closed = false;
|
|
228
|
-
let emittedCount = 0;
|
|
229
|
-
let firstLine = null;
|
|
230
|
-
let lastLine = null;
|
|
231
474
|
worker.on("message", (msg) => {
|
|
232
475
|
if (msg.type === "page") pageQueue.push(msg.data);
|
|
233
476
|
if (msg.type === "done") {
|
|
@@ -235,49 +478,66 @@ function createWorkerReader(filepath, options) {
|
|
|
235
478
|
pageQueue.wake();
|
|
236
479
|
}
|
|
237
480
|
});
|
|
481
|
+
worker.on("error", () => {
|
|
482
|
+
done = true;
|
|
483
|
+
pageQueue.wake();
|
|
484
|
+
});
|
|
485
|
+
worker.on("exit", () => {
|
|
486
|
+
done = true;
|
|
487
|
+
pageQueue.wake();
|
|
488
|
+
});
|
|
238
489
|
async function next() {
|
|
239
490
|
if (closed) return null;
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
return page;
|
|
491
|
+
return await pageQueue.shift(done);
|
|
492
|
+
}
|
|
493
|
+
function nextSync() {
|
|
494
|
+
if (closed) return null;
|
|
495
|
+
return pageQueue.shiftSync();
|
|
246
496
|
}
|
|
247
497
|
async function close() {
|
|
248
498
|
closed = true;
|
|
249
499
|
done = true;
|
|
250
|
-
|
|
500
|
+
pageQueue.clear();
|
|
501
|
+
await worker.terminate();
|
|
502
|
+
}
|
|
503
|
+
function tryClose() {
|
|
504
|
+
close().catch(() => {});
|
|
251
505
|
}
|
|
252
506
|
return {
|
|
253
507
|
next,
|
|
508
|
+
nextSync,
|
|
254
509
|
close,
|
|
255
|
-
get lineCount() {
|
|
256
|
-
return emittedCount;
|
|
257
|
-
},
|
|
258
|
-
get firstLine() {
|
|
259
|
-
return firstLine;
|
|
260
|
-
},
|
|
261
|
-
get lastLine() {
|
|
262
|
-
return lastLine;
|
|
263
|
-
},
|
|
264
510
|
async *[Symbol.asyncIterator]() {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
511
|
+
try {
|
|
512
|
+
while (true) {
|
|
513
|
+
const p = await next();
|
|
514
|
+
if (!p) break;
|
|
515
|
+
yield p;
|
|
516
|
+
}
|
|
517
|
+
} finally {
|
|
518
|
+
tryClose();
|
|
519
|
+
}
|
|
520
|
+
},
|
|
521
|
+
*[Symbol.iterator]() {
|
|
522
|
+
try {
|
|
523
|
+
while (true) {
|
|
524
|
+
const p = nextSync();
|
|
525
|
+
if (!p) break;
|
|
526
|
+
yield p;
|
|
527
|
+
}
|
|
528
|
+
} finally {
|
|
529
|
+
tryClose();
|
|
269
530
|
}
|
|
270
531
|
}
|
|
271
532
|
};
|
|
272
533
|
}
|
|
273
|
-
|
|
274
534
|
//#endregion
|
|
275
535
|
//#region src/main.ts
|
|
276
536
|
function createPager(filepath, options = {}) {
|
|
277
|
-
const { chunkSize = 64 * 1024, pageSize = 1e3, delimiter = "\n", prefetch =
|
|
537
|
+
const { chunkSize = 64 * 1024, pageSize = 1e3, delimiter = "\n", prefetch = 8, backward = false, useWorker = false } = options;
|
|
278
538
|
if (!filepath) throw new Error("filepath required");
|
|
279
|
-
if (pageSize
|
|
280
|
-
if (prefetch
|
|
539
|
+
if (pageSize < 1) throw new RangeError("pageSize must be >= 1");
|
|
540
|
+
if (prefetch < 1) throw new RangeError("prefetch must be >= 1");
|
|
281
541
|
if (backward && useWorker) throw new Error("backward not supported with useWorker");
|
|
282
542
|
return useWorker ? createWorkerReader(filepath, {
|
|
283
543
|
chunkSize,
|
|
@@ -296,7 +556,6 @@ function createPager(filepath, options = {}) {
|
|
|
296
556
|
delimiter
|
|
297
557
|
});
|
|
298
558
|
}
|
|
299
|
-
|
|
300
559
|
//#endregion
|
|
301
560
|
exports.createPager = createPager;
|
|
302
|
-
exports.default = createPager;
|
|
561
|
+
exports.default = createPager;
|
package/dist/main.d.cts
CHANGED
|
@@ -9,12 +9,10 @@ interface PagerOptions extends Partial<ReaderOptions> {
|
|
|
9
9
|
backward?: boolean;
|
|
10
10
|
useWorker?: boolean;
|
|
11
11
|
}
|
|
12
|
-
interface Pager extends AsyncIterable<string[]> {
|
|
12
|
+
interface Pager extends AsyncIterable<string[]>, Iterable<string[]> {
|
|
13
13
|
next(): Promise<string[] | null>;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
readonly firstLine: string | null;
|
|
17
|
-
readonly lastLine: string | null;
|
|
14
|
+
nextSync(): string[] | null;
|
|
15
|
+
close(): Promise<void>;
|
|
18
16
|
}
|
|
19
17
|
//#endregion
|
|
20
18
|
//#region src/main.d.ts
|