readline-pager 0.4.9 → 0.5.1
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 +10 -19
- package/dist/main.cjs +20 -3
- package/dist/main.d.cts +2 -2
- package/dist/main.d.mts +2 -2
- package/dist/main.mjs +20 -3
- package/dist/native-46pCT8Rc.d.cts +35 -0
- package/dist/native-DeBXdY3U.d.mts +35 -0
- package/dist/native.cjs +10 -6
- package/dist/native.d.cts +1 -1
- package/dist/native.d.mts +1 -1
- package/dist/native.mjs +10 -6
- package/package.json +5 -5
- package/dist/native-BNwCco1j.d.cts +0 -27
- package/dist/native-BWytCdQz.d.mts +0 -27
package/README.md
CHANGED
|
@@ -85,6 +85,7 @@ createPager(filepath, {
|
|
|
85
85
|
prefetch?: number, // default: 8
|
|
86
86
|
backward?: boolean, // default: false
|
|
87
87
|
useWorker?: boolean, // default: false
|
|
88
|
+
tryNative?: boolean, // default: true
|
|
88
89
|
});
|
|
89
90
|
```
|
|
90
91
|
|
|
@@ -94,6 +95,10 @@ createPager(filepath, {
|
|
|
94
95
|
- `prefetch` — maximum number of pages buffered internally.
|
|
95
96
|
- `backward` — read the file from end to start.
|
|
96
97
|
- `useWorker` — offload reading to a worker thread (forward reading only).
|
|
98
|
+
- `tryNative` — attempts to use the native reader, falls back to the non-native version if it fails.
|
|
99
|
+
|
|
100
|
+
> **Note:**
|
|
101
|
+
> `createNativePager` supports only `pageSize`, `delimiter`, and `backward` options and does **not** support multi-character delimiters.
|
|
97
102
|
|
|
98
103
|
---
|
|
99
104
|
|
|
@@ -107,7 +112,11 @@ Returns `null` when the end of the file is reached.
|
|
|
107
112
|
|
|
108
113
|
Empty lines are preserved.
|
|
109
114
|
|
|
110
|
-
|
|
115
|
+
> **Note:**
|
|
116
|
+
> Unlike Node.js `readline`, which may skip empty files or leading empty lines, `readline-pager` always returns all lines.
|
|
117
|
+
>
|
|
118
|
+
> - A completely empty file (`0` bytes) produces `[""]` on the first read.
|
|
119
|
+
> - A file containing multiple empty lines returns each line as an empty string.
|
|
111
120
|
|
|
112
121
|
### `pager.nextSync(): string[] | null`
|
|
113
122
|
|
|
@@ -115,30 +124,12 @@ Synchronous version of `pager.next()`.
|
|
|
115
124
|
|
|
116
125
|
Returns the next page immediately or `null` when the end of the file is reached.
|
|
117
126
|
|
|
118
|
-
---
|
|
119
|
-
|
|
120
127
|
### `pager.close(): Promise<void>`
|
|
121
128
|
|
|
122
129
|
Stops reading and releases resources asynchronously. Safe to call at any time.
|
|
123
130
|
|
|
124
131
|
---
|
|
125
132
|
|
|
126
|
-
### `createNativePager(filepath, options?): Pager`
|
|
127
|
-
|
|
128
|
-
Creates a pager backed by the optional native C++ addon.
|
|
129
|
-
|
|
130
|
-
If the native addon is not available for the current platform, this function throws.
|
|
131
|
-
|
|
132
|
-
---
|
|
133
|
-
|
|
134
|
-
> **Note:**
|
|
135
|
-
> Unlike Node.js `readline`, which may skip empty files or leading empty lines, `readline-pager` always returns all lines.
|
|
136
|
-
>
|
|
137
|
-
> - A completely empty file (`0` bytes) produces `[""]` on the first read.
|
|
138
|
-
> - A file containing multiple empty lines returns each line as an empty string.
|
|
139
|
-
|
|
140
|
-
---
|
|
141
|
-
|
|
142
133
|
## 📊 Benchmark
|
|
143
134
|
|
|
144
135
|
Run the benchmark locally:
|
package/dist/main.cjs
CHANGED
|
@@ -532,18 +532,35 @@ function createWorkerReader(filepath, options) {
|
|
|
532
532
|
//#endregion
|
|
533
533
|
//#region src/main.ts
|
|
534
534
|
function createPager(filepath, options = {}) {
|
|
535
|
-
const { chunkSize = 64 * 1024, pageSize = 1e3, delimiter = "\n", prefetch = 8, backward = false, useWorker = false } = options;
|
|
535
|
+
const { chunkSize = 64 * 1024, pageSize = 1e3, delimiter = "\n", prefetch = 8, backward = false, useWorker = false, tryNative = true } = options;
|
|
536
536
|
if (!filepath) throw new Error("filepath required");
|
|
537
537
|
if (pageSize < 1) throw new RangeError("pageSize must be >= 1");
|
|
538
538
|
if (prefetch < 1) throw new RangeError("prefetch must be >= 1");
|
|
539
|
-
if (
|
|
539
|
+
if (useWorker) {
|
|
540
|
+
if (backward) throw new Error("backward not supported with useWorker");
|
|
541
|
+
if (tryNative) throw new Error("tryNative not supported with useWorker");
|
|
542
|
+
}
|
|
543
|
+
if (tryNative) {
|
|
544
|
+
if (delimiter.length !== 1) throw new RangeError("native reader only supports single-character delimiters");
|
|
545
|
+
}
|
|
540
546
|
const _options = {
|
|
541
547
|
chunkSize,
|
|
542
548
|
pageSize,
|
|
543
549
|
prefetch,
|
|
544
550
|
delimiter
|
|
545
551
|
};
|
|
546
|
-
|
|
552
|
+
let nativeReader;
|
|
553
|
+
if (tryNative) {
|
|
554
|
+
const _nativeOptions = {
|
|
555
|
+
pageSize,
|
|
556
|
+
delimiter,
|
|
557
|
+
backward
|
|
558
|
+
};
|
|
559
|
+
try {
|
|
560
|
+
nativeReader = require_native.createNativePager(filepath, _nativeOptions);
|
|
561
|
+
} catch {}
|
|
562
|
+
}
|
|
563
|
+
const reader = tryNative && nativeReader ? nativeReader : useWorker ? createWorkerReader(filepath, _options) : backward ? createBackwardReader(filepath, _options) : createForwardReader(filepath, _options);
|
|
547
564
|
if (process.env.TEST_CLEANUPS) {
|
|
548
565
|
globalThis.__test_cleanups__ ??= [];
|
|
549
566
|
globalThis.__test_cleanups__.push(reader.close);
|
package/dist/main.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as NativeReaderOptions, c as ReaderOptions, i as NativeAddon, n as AddonData, o as Pager, r as AddonFD, s as PagerOptions, t as createNativePager } from "./native-46pCT8Rc.cjs";
|
|
2
2
|
|
|
3
3
|
//#region src/main.d.ts
|
|
4
4
|
declare function createPager(filepath: string, options?: PagerOptions): Pager;
|
|
5
5
|
//#endregion
|
|
6
|
-
export { Pager, PagerOptions, ReaderOptions, createNativePager, createPager, createPager as default };
|
|
6
|
+
export { AddonData, AddonFD, NativeAddon, NativeReaderOptions, Pager, PagerOptions, ReaderOptions, createNativePager, createPager, createPager as default };
|
package/dist/main.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as NativeReaderOptions, c as ReaderOptions, i as NativeAddon, n as AddonData, o as Pager, r as AddonFD, s as PagerOptions, t as createNativePager } from "./native-DeBXdY3U.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/main.d.ts
|
|
4
4
|
declare function createPager(filepath: string, options?: PagerOptions): Pager;
|
|
5
5
|
//#endregion
|
|
6
|
-
export { Pager, PagerOptions, ReaderOptions, createNativePager, createPager, createPager as default };
|
|
6
|
+
export { AddonData, AddonFD, NativeAddon, NativeReaderOptions, Pager, PagerOptions, ReaderOptions, createNativePager, createPager, createPager as default };
|
package/dist/main.mjs
CHANGED
|
@@ -532,18 +532,35 @@ function createWorkerReader(filepath, options) {
|
|
|
532
532
|
//#endregion
|
|
533
533
|
//#region src/main.ts
|
|
534
534
|
function createPager(filepath, options = {}) {
|
|
535
|
-
const { chunkSize = 64 * 1024, pageSize = 1e3, delimiter = "\n", prefetch = 8, backward = false, useWorker = false } = options;
|
|
535
|
+
const { chunkSize = 64 * 1024, pageSize = 1e3, delimiter = "\n", prefetch = 8, backward = false, useWorker = false, tryNative = true } = options;
|
|
536
536
|
if (!filepath) throw new Error("filepath required");
|
|
537
537
|
if (pageSize < 1) throw new RangeError("pageSize must be >= 1");
|
|
538
538
|
if (prefetch < 1) throw new RangeError("prefetch must be >= 1");
|
|
539
|
-
if (
|
|
539
|
+
if (useWorker) {
|
|
540
|
+
if (backward) throw new Error("backward not supported with useWorker");
|
|
541
|
+
if (tryNative) throw new Error("tryNative not supported with useWorker");
|
|
542
|
+
}
|
|
543
|
+
if (tryNative) {
|
|
544
|
+
if (delimiter.length !== 1) throw new RangeError("native reader only supports single-character delimiters");
|
|
545
|
+
}
|
|
540
546
|
const _options = {
|
|
541
547
|
chunkSize,
|
|
542
548
|
pageSize,
|
|
543
549
|
prefetch,
|
|
544
550
|
delimiter
|
|
545
551
|
};
|
|
546
|
-
|
|
552
|
+
let nativeReader;
|
|
553
|
+
if (tryNative) {
|
|
554
|
+
const _nativeOptions = {
|
|
555
|
+
pageSize,
|
|
556
|
+
delimiter,
|
|
557
|
+
backward
|
|
558
|
+
};
|
|
559
|
+
try {
|
|
560
|
+
nativeReader = createNativePager(filepath, _nativeOptions);
|
|
561
|
+
} catch {}
|
|
562
|
+
}
|
|
563
|
+
const reader = tryNative && nativeReader ? nativeReader : useWorker ? createWorkerReader(filepath, _options) : backward ? createBackwardReader(filepath, _options) : createForwardReader(filepath, _options);
|
|
547
564
|
if (process.env.TEST_CLEANUPS) {
|
|
548
565
|
globalThis.__test_cleanups__ ??= [];
|
|
549
566
|
globalThis.__test_cleanups__.push(reader.close);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
2
|
+
interface ReaderOptions {
|
|
3
|
+
chunkSize: number;
|
|
4
|
+
pageSize: number;
|
|
5
|
+
delimiter: string;
|
|
6
|
+
prefetch: number;
|
|
7
|
+
}
|
|
8
|
+
interface PagerOptions extends Partial<ReaderOptions> {
|
|
9
|
+
backward?: boolean;
|
|
10
|
+
useWorker?: boolean;
|
|
11
|
+
tryNative?: boolean;
|
|
12
|
+
}
|
|
13
|
+
interface Pager extends AsyncIterable<string[]>, Iterable<string[]> {
|
|
14
|
+
next(): Promise<string[] | null>;
|
|
15
|
+
nextSync(): string[] | null;
|
|
16
|
+
close(): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
interface NativeReaderOptions {
|
|
19
|
+
pageSize: number;
|
|
20
|
+
delimiter: string;
|
|
21
|
+
backward: boolean;
|
|
22
|
+
}
|
|
23
|
+
type AddonFD = object | null;
|
|
24
|
+
type AddonData = Buffer | null;
|
|
25
|
+
interface NativeAddon {
|
|
26
|
+
open: (filepath: string, pageSize: number, delimiter: string, backward: boolean) => AddonFD;
|
|
27
|
+
next: (fd: AddonFD) => Promise<AddonData>;
|
|
28
|
+
nextSync: (fd: AddonFD) => AddonData;
|
|
29
|
+
close: (fd: AddonFD) => Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/native.d.ts
|
|
33
|
+
declare function createNativePager(filepath: string, options?: Partial<NativeReaderOptions>): Pager;
|
|
34
|
+
//#endregion
|
|
35
|
+
export { NativeReaderOptions as a, ReaderOptions as c, NativeAddon as i, AddonData as n, Pager as o, AddonFD as r, PagerOptions as s, createNativePager as t };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
2
|
+
interface ReaderOptions {
|
|
3
|
+
chunkSize: number;
|
|
4
|
+
pageSize: number;
|
|
5
|
+
delimiter: string;
|
|
6
|
+
prefetch: number;
|
|
7
|
+
}
|
|
8
|
+
interface PagerOptions extends Partial<ReaderOptions> {
|
|
9
|
+
backward?: boolean;
|
|
10
|
+
useWorker?: boolean;
|
|
11
|
+
tryNative?: boolean;
|
|
12
|
+
}
|
|
13
|
+
interface Pager extends AsyncIterable<string[]>, Iterable<string[]> {
|
|
14
|
+
next(): Promise<string[] | null>;
|
|
15
|
+
nextSync(): string[] | null;
|
|
16
|
+
close(): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
interface NativeReaderOptions {
|
|
19
|
+
pageSize: number;
|
|
20
|
+
delimiter: string;
|
|
21
|
+
backward: boolean;
|
|
22
|
+
}
|
|
23
|
+
type AddonFD = object | null;
|
|
24
|
+
type AddonData = Buffer | null;
|
|
25
|
+
interface NativeAddon {
|
|
26
|
+
open: (filepath: string, pageSize: number, delimiter: string, backward: boolean) => AddonFD;
|
|
27
|
+
next: (fd: AddonFD) => Promise<AddonData>;
|
|
28
|
+
nextSync: (fd: AddonFD) => AddonData;
|
|
29
|
+
close: (fd: AddonFD) => Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/native.d.ts
|
|
33
|
+
declare function createNativePager(filepath: string, options?: Partial<NativeReaderOptions>): Pager;
|
|
34
|
+
//#endregion
|
|
35
|
+
export { NativeReaderOptions as a, ReaderOptions as c, NativeAddon as i, AddonData as n, Pager as o, AddonFD as r, PagerOptions as s, createNativePager as t };
|
package/dist/native.cjs
CHANGED
|
@@ -29,29 +29,33 @@ function loadNativeAddon() {
|
|
|
29
29
|
throw new Error(UNAVAILABLE);
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
-
function createNativePager(filepath,
|
|
33
|
-
const
|
|
32
|
+
function createNativePager(filepath, options) {
|
|
33
|
+
const { pageSize = 1e3, delimiter = "\n", backward = false } = options ?? {};
|
|
34
|
+
if (!filepath) throw new Error("filepath required");
|
|
35
|
+
if (pageSize < 1) throw new RangeError("pageSize must be >= 1");
|
|
36
|
+
if (delimiter.length !== 1) throw new RangeError("native reader only supports single-character delimiters");
|
|
37
|
+
const nativePager = loadNativeAddon();
|
|
34
38
|
let fd = null;
|
|
35
39
|
let closed = false;
|
|
36
40
|
const init = () => {
|
|
37
|
-
fd =
|
|
41
|
+
fd = nativePager.open(filepath, pageSize, delimiter, backward);
|
|
38
42
|
};
|
|
39
43
|
const next = async () => {
|
|
40
44
|
if (closed || !fd) return null;
|
|
41
|
-
const data = await
|
|
45
|
+
const data = await nativePager.next(fd);
|
|
42
46
|
if (!data) return null;
|
|
43
47
|
return data.toString("utf8").split(delimiter);
|
|
44
48
|
};
|
|
45
49
|
const nextSync = () => {
|
|
46
50
|
if (closed || !fd) return null;
|
|
47
|
-
const data =
|
|
51
|
+
const data = nativePager.nextSync(fd);
|
|
48
52
|
if (!data) return null;
|
|
49
53
|
return data.toString("utf8").split(delimiter);
|
|
50
54
|
};
|
|
51
55
|
const close = async () => {
|
|
52
56
|
if (!closed || fd) {
|
|
53
57
|
closed = true;
|
|
54
|
-
await
|
|
58
|
+
await nativePager.close(fd);
|
|
55
59
|
fd = null;
|
|
56
60
|
}
|
|
57
61
|
};
|
package/dist/native.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as createNativePager } from "./native-
|
|
1
|
+
import { t as createNativePager } from "./native-46pCT8Rc.cjs";
|
|
2
2
|
export { createNativePager };
|
package/dist/native.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as createNativePager } from "./native-
|
|
1
|
+
import { t as createNativePager } from "./native-DeBXdY3U.mjs";
|
|
2
2
|
export { createNativePager };
|
package/dist/native.mjs
CHANGED
|
@@ -28,29 +28,33 @@ function loadNativeAddon() {
|
|
|
28
28
|
throw new Error(UNAVAILABLE);
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
-
function createNativePager(filepath,
|
|
32
|
-
const
|
|
31
|
+
function createNativePager(filepath, options) {
|
|
32
|
+
const { pageSize = 1e3, delimiter = "\n", backward = false } = options ?? {};
|
|
33
|
+
if (!filepath) throw new Error("filepath required");
|
|
34
|
+
if (pageSize < 1) throw new RangeError("pageSize must be >= 1");
|
|
35
|
+
if (delimiter.length !== 1) throw new RangeError("native reader only supports single-character delimiters");
|
|
36
|
+
const nativePager = loadNativeAddon();
|
|
33
37
|
let fd = null;
|
|
34
38
|
let closed = false;
|
|
35
39
|
const init = () => {
|
|
36
|
-
fd =
|
|
40
|
+
fd = nativePager.open(filepath, pageSize, delimiter, backward);
|
|
37
41
|
};
|
|
38
42
|
const next = async () => {
|
|
39
43
|
if (closed || !fd) return null;
|
|
40
|
-
const data = await
|
|
44
|
+
const data = await nativePager.next(fd);
|
|
41
45
|
if (!data) return null;
|
|
42
46
|
return data.toString("utf8").split(delimiter);
|
|
43
47
|
};
|
|
44
48
|
const nextSync = () => {
|
|
45
49
|
if (closed || !fd) return null;
|
|
46
|
-
const data =
|
|
50
|
+
const data = nativePager.nextSync(fd);
|
|
47
51
|
if (!data) return null;
|
|
48
52
|
return data.toString("utf8").split(delimiter);
|
|
49
53
|
};
|
|
50
54
|
const close = async () => {
|
|
51
55
|
if (!closed || fd) {
|
|
52
56
|
closed = true;
|
|
53
|
-
await
|
|
57
|
+
await nativePager.close(fd);
|
|
54
58
|
fd = null;
|
|
55
59
|
}
|
|
56
60
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "readline-pager",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"build:js": "tsdown",
|
|
6
6
|
"build:native": "node-gyp rebuild",
|
|
@@ -24,10 +24,10 @@
|
|
|
24
24
|
"typescript": "~6.0.2"
|
|
25
25
|
},
|
|
26
26
|
"optionalDependencies": {
|
|
27
|
-
"@devmor-j/readline-pager-linux-arm64": "0.
|
|
28
|
-
"@devmor-j/readline-pager-linux-
|
|
29
|
-
"@devmor-j/readline-pager-linux-musl-
|
|
30
|
-
"@devmor-j/readline-pager-linux-
|
|
27
|
+
"@devmor-j/readline-pager-linux-arm64": "0.5.1",
|
|
28
|
+
"@devmor-j/readline-pager-linux-musl-arm64": "0.5.1",
|
|
29
|
+
"@devmor-j/readline-pager-linux-musl-x64": "0.5.1",
|
|
30
|
+
"@devmor-j/readline-pager-linux-x64": "0.5.1"
|
|
31
31
|
},
|
|
32
32
|
"gypfile": false,
|
|
33
33
|
"type": "module",
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
//#region src/types.d.ts
|
|
2
|
-
interface ReaderOptions {
|
|
3
|
-
chunkSize: number;
|
|
4
|
-
pageSize: number;
|
|
5
|
-
delimiter: string;
|
|
6
|
-
prefetch: number;
|
|
7
|
-
}
|
|
8
|
-
interface PagerOptions extends Partial<ReaderOptions> {
|
|
9
|
-
backward?: boolean;
|
|
10
|
-
useWorker?: boolean;
|
|
11
|
-
}
|
|
12
|
-
interface Pager extends AsyncIterable<string[]>, Iterable<string[]> {
|
|
13
|
-
next(): Promise<string[] | null>;
|
|
14
|
-
nextSync(): string[] | null;
|
|
15
|
-
close(): Promise<void>;
|
|
16
|
-
}
|
|
17
|
-
//#endregion
|
|
18
|
-
//#region src/native.d.ts
|
|
19
|
-
declare function createNativePager(filepath: string, {
|
|
20
|
-
pageSize,
|
|
21
|
-
delimiter
|
|
22
|
-
}?: {
|
|
23
|
-
pageSize?: number | undefined;
|
|
24
|
-
delimiter?: string | undefined;
|
|
25
|
-
}): Pager;
|
|
26
|
-
//#endregion
|
|
27
|
-
export { ReaderOptions as i, Pager as n, PagerOptions as r, createNativePager as t };
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
//#region src/types.d.ts
|
|
2
|
-
interface ReaderOptions {
|
|
3
|
-
chunkSize: number;
|
|
4
|
-
pageSize: number;
|
|
5
|
-
delimiter: string;
|
|
6
|
-
prefetch: number;
|
|
7
|
-
}
|
|
8
|
-
interface PagerOptions extends Partial<ReaderOptions> {
|
|
9
|
-
backward?: boolean;
|
|
10
|
-
useWorker?: boolean;
|
|
11
|
-
}
|
|
12
|
-
interface Pager extends AsyncIterable<string[]>, Iterable<string[]> {
|
|
13
|
-
next(): Promise<string[] | null>;
|
|
14
|
-
nextSync(): string[] | null;
|
|
15
|
-
close(): Promise<void>;
|
|
16
|
-
}
|
|
17
|
-
//#endregion
|
|
18
|
-
//#region src/native.d.ts
|
|
19
|
-
declare function createNativePager(filepath: string, {
|
|
20
|
-
pageSize,
|
|
21
|
-
delimiter
|
|
22
|
-
}?: {
|
|
23
|
-
pageSize?: number | undefined;
|
|
24
|
-
delimiter?: string | undefined;
|
|
25
|
-
}): Pager;
|
|
26
|
-
//#endregion
|
|
27
|
-
export { ReaderOptions as i, Pager as n, PagerOptions as r, createNativePager as t };
|