readline-pager 0.2.6 → 0.2.7

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 CHANGED
@@ -100,7 +100,7 @@ Returns the next page or `null` when finished. Empty lines are preserved.
100
100
  - A completely empty file (`0` bytes) produces `[""]` on the first read.
101
101
  - A file with multiple empty lines returns each line as an empty string (e.g., `["", ""]` for two empty lines). Node.js `readline` may emit fewer or no `line` events in these cases.
102
102
 
103
- ### `pager.close(): void`
103
+ ### `pager.close(): Promise<void>`
104
104
 
105
105
  Stops reading and releases resources immediately. Safe to call at any time.
106
106
 
@@ -118,21 +118,39 @@ Run the included benchmark:
118
118
 
119
119
  ```bash
120
120
  # default run
121
- node test/_benchmark.ts
121
+ npm run benchmark
122
122
 
123
123
  # or customize with args
124
124
  node test/_benchmark.ts --lines=20000 --page-size=500 --backward
125
125
  ```
126
126
 
127
127
  > Test setup: generated text files with uuid, run on a fast NVMe machine with default options; values are averages from multiple runs. Results are machine-dependent.
128
-
129
- | Lines | File MB | Node `readline` (MB/s) | Bun streaming (MB/s) | `readline-pager` (Node) (MB/s) |
130
- | -----: | -------: | ---------------------: | -------------------: | -----------------------------: |
131
- | 10M | 352.86 | ~423 | ~296 | **~1,327** |
132
- | 100M | 3528.59 | ~441 | ~298 | **~1,378** |
133
- | 1,000M | 35285.95 | ~426 | ~294 | **~1,168** |
134
-
135
- **Runtime Environment:** Node.js v25.6.1 & Bun v1.3.9
128
+ >
129
+ > The **Average Throughput (MB/s)** is computed for two strategies: reading files line by line and page by page.
130
+ >
131
+ > In addition to _Node_, the two other popular JavaScript runtimes were also tested with `readline-pager`.
132
+
133
+ ### Line by line
134
+
135
+ | Runtime / Method | 1M lines (35 MB) | 10M lines (353 MB) | 100M lines (3,529 MB) | 1,000M lines (35,286 MB) |
136
+ | ---------------- | ---------------: | -----------------: | --------------------: | -----------------------: |
137
+ | Node — node:line | 369 | 435 | 455 | 455 |
138
+ | Deno — node:line | 203 | 230 | 230 | 229 |
139
+ | Deno — deno:line | 738 | 901 | 915 | 809 |
140
+ | Bun — node:line | 246 | 279 | 283 | 280 |
141
+ | Bun — bun:line | 938 | 1,540 | 1,668 | 1,315 |
142
+
143
+ ### Page by page
144
+
145
+ | Runtime / Method | 1M lines (35 MB) | 10M lines (353 MB) | 100M lines (3,529 MB) | 1,000M lines (35,286 MB) |
146
+ | --------------------- | ---------------: | -----------------: | --------------------: | -----------------------: |
147
+ | Node — readline-pager | 1,053 | 1,311 | 1,278 | 936 |
148
+ | Deno — deno:page | 852 | 909 | 908 | 783 |
149
+ | Deno — readline-pager | 1,131 | 1,268 | 1,271 | 911 |
150
+ | Bun — bun:page | 411 | 440 | 449 | 428 |
151
+ | Bun — readline-pager | 827 | 1,021 | 1,040 | 804 |
152
+
153
+ **Runtime Environment:** Node.js v25.6.1 & Bun v1.3.9 & Deno 2.6.10
136
154
 
137
155
  ---
138
156
 
package/dist/main.cjs CHANGED
@@ -98,7 +98,10 @@ function createBackwardReader(filepath, options) {
98
98
  closed = true;
99
99
  done = true;
100
100
  pageQueue.queue.length = 0;
101
- if (fd) await fd.close();
101
+ if (fd) {
102
+ await fd.close();
103
+ fd = null;
104
+ }
102
105
  }
103
106
  return {
104
107
  next,
@@ -113,10 +116,14 @@ function createBackwardReader(filepath, options) {
113
116
  return lastLine;
114
117
  },
115
118
  async *[Symbol.asyncIterator]() {
116
- while (true) {
117
- const p = await next();
118
- if (!p) break;
119
- yield p;
119
+ try {
120
+ while (true) {
121
+ const p = await next();
122
+ if (!p) break;
123
+ yield p;
124
+ }
125
+ } finally {
126
+ await close().catch(() => {});
120
127
  }
121
128
  }
122
129
  };
@@ -187,7 +194,10 @@ function createForwardReader(filepath, options) {
187
194
  closed = true;
188
195
  done = true;
189
196
  pageQueue.queue.length = 0;
190
- if (fd) await fd.close();
197
+ if (fd) {
198
+ await fd.close();
199
+ fd = null;
200
+ }
191
201
  }
192
202
  return {
193
203
  next,
@@ -202,10 +212,14 @@ function createForwardReader(filepath, options) {
202
212
  return lastLine;
203
213
  },
204
214
  async *[Symbol.asyncIterator]() {
205
- while (true) {
206
- const p = await next();
207
- if (!p) break;
208
- yield p;
215
+ try {
216
+ while (true) {
217
+ const p = await next();
218
+ if (!p) break;
219
+ yield p;
220
+ }
221
+ } finally {
222
+ await close();
209
223
  }
210
224
  }
211
225
  };
@@ -247,7 +261,7 @@ function createWorkerReader(filepath, options) {
247
261
  async function close() {
248
262
  closed = true;
249
263
  done = true;
250
- worker.terminate();
264
+ await worker.terminate();
251
265
  }
252
266
  return {
253
267
  next,
@@ -262,10 +276,14 @@ function createWorkerReader(filepath, options) {
262
276
  return lastLine;
263
277
  },
264
278
  async *[Symbol.asyncIterator]() {
265
- while (true) {
266
- const p = await next();
267
- if (!p) break;
268
- yield p;
279
+ try {
280
+ while (true) {
281
+ const p = await next();
282
+ if (!p) break;
283
+ yield p;
284
+ }
285
+ } finally {
286
+ await close();
269
287
  }
270
288
  }
271
289
  };
package/dist/main.d.cts CHANGED
@@ -11,7 +11,7 @@ interface PagerOptions extends Partial<ReaderOptions> {
11
11
  }
12
12
  interface Pager extends AsyncIterable<string[]> {
13
13
  next(): Promise<string[] | null>;
14
- close(): void;
14
+ close(): Promise<void>;
15
15
  readonly lineCount: number;
16
16
  readonly firstLine: string | null;
17
17
  readonly lastLine: string | null;
package/dist/main.d.mts CHANGED
@@ -11,7 +11,7 @@ interface PagerOptions extends Partial<ReaderOptions> {
11
11
  }
12
12
  interface Pager extends AsyncIterable<string[]> {
13
13
  next(): Promise<string[] | null>;
14
- close(): void;
14
+ close(): Promise<void>;
15
15
  readonly lineCount: number;
16
16
  readonly firstLine: string | null;
17
17
  readonly lastLine: string | null;
package/dist/main.mjs CHANGED
@@ -102,7 +102,10 @@ function createBackwardReader(filepath, options) {
102
102
  closed = true;
103
103
  done = true;
104
104
  pageQueue.queue.length = 0;
105
- if (fd) await fd.close();
105
+ if (fd) {
106
+ await fd.close();
107
+ fd = null;
108
+ }
106
109
  }
107
110
  return {
108
111
  next,
@@ -117,10 +120,14 @@ function createBackwardReader(filepath, options) {
117
120
  return lastLine;
118
121
  },
119
122
  async *[Symbol.asyncIterator]() {
120
- while (true) {
121
- const p = await next();
122
- if (!p) break;
123
- yield p;
123
+ try {
124
+ while (true) {
125
+ const p = await next();
126
+ if (!p) break;
127
+ yield p;
128
+ }
129
+ } finally {
130
+ await close().catch(() => {});
124
131
  }
125
132
  }
126
133
  };
@@ -191,7 +198,10 @@ function createForwardReader(filepath, options) {
191
198
  closed = true;
192
199
  done = true;
193
200
  pageQueue.queue.length = 0;
194
- if (fd) await fd.close();
201
+ if (fd) {
202
+ await fd.close();
203
+ fd = null;
204
+ }
195
205
  }
196
206
  return {
197
207
  next,
@@ -206,10 +216,14 @@ function createForwardReader(filepath, options) {
206
216
  return lastLine;
207
217
  },
208
218
  async *[Symbol.asyncIterator]() {
209
- while (true) {
210
- const p = await next();
211
- if (!p) break;
212
- yield p;
219
+ try {
220
+ while (true) {
221
+ const p = await next();
222
+ if (!p) break;
223
+ yield p;
224
+ }
225
+ } finally {
226
+ await close();
213
227
  }
214
228
  }
215
229
  };
@@ -251,7 +265,7 @@ function createWorkerReader(filepath, options) {
251
265
  async function close() {
252
266
  closed = true;
253
267
  done = true;
254
- worker.terminate();
268
+ await worker.terminate();
255
269
  }
256
270
  return {
257
271
  next,
@@ -266,10 +280,14 @@ function createWorkerReader(filepath, options) {
266
280
  return lastLine;
267
281
  },
268
282
  async *[Symbol.asyncIterator]() {
269
- while (true) {
270
- const p = await next();
271
- if (!p) break;
272
- yield p;
283
+ try {
284
+ while (true) {
285
+ const p = await next();
286
+ if (!p) break;
287
+ yield p;
288
+ }
289
+ } finally {
290
+ await close();
273
291
  }
274
292
  }
275
293
  };
package/package.json CHANGED
@@ -1,14 +1,16 @@
1
1
  {
2
2
  "name": "readline-pager",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "scripts": {
5
5
  "build": "tsdown",
6
6
  "pretest": "npm run build",
7
7
  "test": "node --test --experimental-test-coverage test/**/*.test.ts",
8
- "prepublishOnly": "npm run build && npm run test"
8
+ "prepublishOnly": "npm run build && npm run test",
9
+ "benchmark": "node test/_benchmark.ts; bun test/_benchmark.ts; deno --allow-write --allow-read test/_benchmark.ts"
9
10
  },
10
11
  "devDependencies": {
11
12
  "@types/bun": "~1.3.9",
13
+ "@types/deno": "~2.5.0",
12
14
  "@types/node": "~25.3.0",
13
15
  "prettier": "~3.8.1",
14
16
  "prettier-plugin-organize-imports": "~4.3.0",