readline-pager 0.6.2 → 0.6.5

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
@@ -68,7 +68,7 @@ let page;
68
68
  const pager = createPager("./bigfile.txt");
69
69
  while ((page = pager.nextSync()) !== null) {}
70
70
 
71
- // Native C++ (fastest)
71
+ // Native C++
72
72
  for await (const page of createNativePager("./bigfile.txt")) {
73
73
  }
74
74
  ```
@@ -87,6 +87,12 @@ createPager(filepath, {
87
87
  useWorker?: boolean, // default: false
88
88
  tryNative?: boolean, // default: true
89
89
  });
90
+
91
+ createNativePager(filepath, {
92
+ pageSize?: number, // default: 1_000
93
+ delimiter?: string, // default: "\n"
94
+ backward?: boolean, // default: false
95
+ });
90
96
  ```
91
97
 
92
98
  - `chunkSize` — number of bytes read per I/O operation.
@@ -98,7 +104,7 @@ createPager(filepath, {
98
104
  - `tryNative` — attempts to use the native reader, falls back to the non-native version if it fails.
99
105
 
100
106
  > **Note:**
101
- > `createNativePager` supports only `pageSize`, `delimiter`, and `backward` options and does **not** support multi-character delimiters.
107
+ > `createNativePager` requires x86 AVX2 or ARM NEON CPU instruction set extensions and will throw if they are not available. It also does **not** support multi-character delimiters due to fast SIMD-based scanning.
102
108
 
103
109
  ---
104
110
 
@@ -138,7 +144,7 @@ Run the benchmark locally:
138
144
  npm run benchmark:node
139
145
 
140
146
  # or customize with args
141
- node test/_benchmark.ts --lines=20000 --page-size=500 --backward
147
+ node test/benchmark.ts --lines=20000 --page-size=500 --backward
142
148
  ```
143
149
 
144
150
  > Test setup: generated text files (UUID lines), NVMe SSD, Node.js runtime.
package/dist/main.cjs CHANGED
@@ -529,7 +529,7 @@ function createPager(filepath, options = {}) {
529
529
  if (tryNative) {
530
530
  if (delimiter.length !== 1) throw new RangeError("native reader only supports single-character delimiters");
531
531
  }
532
- const _options = {
532
+ const readerOptions = {
533
533
  chunkSize,
534
534
  pageSize,
535
535
  prefetch,
@@ -537,19 +537,19 @@ function createPager(filepath, options = {}) {
537
537
  };
538
538
  let nativeReader;
539
539
  if (tryNative) {
540
- const _nativeOptions = {
540
+ const nativeOptions = {
541
541
  pageSize,
542
542
  delimiter,
543
543
  backward
544
544
  };
545
545
  try {
546
- nativeReader = require_native.createNativePager(filepath, _nativeOptions);
546
+ nativeReader = require_native.createNativePager(filepath, nativeOptions);
547
547
  } catch {}
548
548
  }
549
- const reader = tryNative && nativeReader ? nativeReader : useWorker ? createWorkerReader(filepath, _options) : backward ? createBackwardReader(filepath, _options) : createForwardReader(filepath, _options);
550
- if (process.env.TEST_CLEANUPS) {
551
- globalThis.__test_cleanups__ ??= [];
552
- globalThis.__test_cleanups__.push(reader.close);
549
+ const reader = tryNative && nativeReader ? nativeReader : useWorker ? createWorkerReader(filepath, readerOptions) : backward ? createBackwardReader(filepath, readerOptions) : createForwardReader(filepath, readerOptions);
550
+ if (process.env.PAGER_TEST_CLEANUPS) {
551
+ globalThis.__pager_test_cleanups__ ??= [];
552
+ globalThis.__pager_test_cleanups__.push(reader.close);
553
553
  }
554
554
  return reader;
555
555
  }
package/dist/main.mjs CHANGED
@@ -529,7 +529,7 @@ function createPager(filepath, options = {}) {
529
529
  if (tryNative) {
530
530
  if (delimiter.length !== 1) throw new RangeError("native reader only supports single-character delimiters");
531
531
  }
532
- const _options = {
532
+ const readerOptions = {
533
533
  chunkSize,
534
534
  pageSize,
535
535
  prefetch,
@@ -537,19 +537,19 @@ function createPager(filepath, options = {}) {
537
537
  };
538
538
  let nativeReader;
539
539
  if (tryNative) {
540
- const _nativeOptions = {
540
+ const nativeOptions = {
541
541
  pageSize,
542
542
  delimiter,
543
543
  backward
544
544
  };
545
545
  try {
546
- nativeReader = createNativePager(filepath, _nativeOptions);
546
+ nativeReader = createNativePager(filepath, nativeOptions);
547
547
  } catch {}
548
548
  }
549
- const reader = tryNative && nativeReader ? nativeReader : useWorker ? createWorkerReader(filepath, _options) : backward ? createBackwardReader(filepath, _options) : createForwardReader(filepath, _options);
550
- if (process.env.TEST_CLEANUPS) {
551
- globalThis.__test_cleanups__ ??= [];
552
- globalThis.__test_cleanups__.push(reader.close);
549
+ const reader = tryNative && nativeReader ? nativeReader : useWorker ? createWorkerReader(filepath, readerOptions) : backward ? createBackwardReader(filepath, readerOptions) : createForwardReader(filepath, readerOptions);
550
+ if (process.env.PAGER_TEST_CLEANUPS) {
551
+ globalThis.__pager_test_cleanups__ ??= [];
552
+ globalThis.__pager_test_cleanups__.push(reader.close);
553
553
  }
554
554
  return reader;
555
555
  }
package/dist/native.cjs CHANGED
@@ -7,16 +7,13 @@ function isMusl() {
7
7
  if ((0, node_os.platform)() !== "linux") return false;
8
8
  try {
9
9
  return !(process.report?.getReport?.())?.header?.glibcVersionRuntime;
10
- } catch {
11
- return false;
12
- }
10
+ } catch {}
11
+ return false;
13
12
  }
14
13
  function getPackageName() {
15
14
  const p = (0, node_os.platform)();
16
15
  const a = (0, node_os.arch)();
17
16
  switch (p) {
18
- case "darwin":
19
- case "win32": return `@devmor-j/readline-pager-${p}-${a}`;
20
17
  case "linux": return `@devmor-j/readline-pager-${p}-${isMusl() ? "musl-" : ""}${a}`;
21
18
  default: throw new Error(`Unsupported platform: ${p}/${a}`);
22
19
  }
@@ -25,40 +22,45 @@ function loadNativeAddon() {
25
22
  try {
26
23
  return require$1(getPackageName());
27
24
  } catch {
28
- const UNAVAILABLE = `Native addon not available for ${(0, node_os.platform)()}/${(0, node_os.arch)()}.`;
29
- throw new Error(UNAVAILABLE);
25
+ const p = (0, node_os.platform)();
26
+ const a = (0, node_os.arch)();
27
+ throw new Error(`Native addon not available for ${p}/${a}.`);
30
28
  }
31
29
  }
32
- function createNativePager(filepath, options) {
33
- const { pageSize = 1e3, delimiter = "\n", backward = false } = options ?? {};
30
+ function createNativePager(filepath, options = {}) {
31
+ const { pageSize = 1e3, delimiter = "\n", backward = false } = options;
34
32
  if (!filepath) throw new Error("filepath required");
35
33
  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();
38
- let fd = nativePager.open(filepath, pageSize, delimiter, backward);
34
+ if (delimiter?.length > 1) throw new RangeError("native reader only supports single-character delimiters");
35
+ const nativeReader = loadNativeAddon();
36
+ if (process.env.PAGER_TEST_CLEANUPS) {
37
+ globalThis.__pager_test_cleanups__ ??= [];
38
+ globalThis.__pager_test_cleanups__.push(nativeReader.close);
39
+ }
40
+ let fd = nativeReader.open(filepath, pageSize, delimiter, backward);
39
41
  let closed = false;
40
- const next = async () => {
42
+ async function next() {
41
43
  if (closed || !fd) return null;
42
- const data = await nativePager.next(fd);
44
+ const data = await nativeReader.next(fd);
43
45
  if (!data) return null;
44
46
  return data.toString("utf8").split(delimiter);
45
- };
46
- const nextSync = () => {
47
+ }
48
+ function nextSync() {
47
49
  if (closed || !fd) return null;
48
- const data = nativePager.nextSync(fd);
50
+ const data = nativeReader.nextSync(fd);
49
51
  if (!data) return null;
50
52
  return data.toString("utf8").split(delimiter);
51
- };
52
- const close = async () => {
53
- if (closed) return;
53
+ }
54
+ async function close() {
55
+ if (closed || !fd) return;
54
56
  closed = true;
55
57
  if (fd) {
56
58
  try {
57
- await nativePager.close(fd);
59
+ await nativeReader.close(fd);
58
60
  } catch {}
59
61
  fd = null;
60
62
  }
61
- };
63
+ }
62
64
  function tryClose() {
63
65
  close().catch(() => {});
64
66
  }
package/dist/native.mjs CHANGED
@@ -6,16 +6,13 @@ function isMusl() {
6
6
  if (platform() !== "linux") return false;
7
7
  try {
8
8
  return !(process.report?.getReport?.())?.header?.glibcVersionRuntime;
9
- } catch {
10
- return false;
11
- }
9
+ } catch {}
10
+ return false;
12
11
  }
13
12
  function getPackageName() {
14
13
  const p = platform();
15
14
  const a = arch();
16
15
  switch (p) {
17
- case "darwin":
18
- case "win32": return `@devmor-j/readline-pager-${p}-${a}`;
19
16
  case "linux": return `@devmor-j/readline-pager-${p}-${isMusl() ? "musl-" : ""}${a}`;
20
17
  default: throw new Error(`Unsupported platform: ${p}/${a}`);
21
18
  }
@@ -24,40 +21,45 @@ function loadNativeAddon() {
24
21
  try {
25
22
  return require(getPackageName());
26
23
  } catch {
27
- const UNAVAILABLE = `Native addon not available for ${platform()}/${arch()}.`;
28
- throw new Error(UNAVAILABLE);
24
+ const p = platform();
25
+ const a = arch();
26
+ throw new Error(`Native addon not available for ${p}/${a}.`);
29
27
  }
30
28
  }
31
- function createNativePager(filepath, options) {
32
- const { pageSize = 1e3, delimiter = "\n", backward = false } = options ?? {};
29
+ function createNativePager(filepath, options = {}) {
30
+ const { pageSize = 1e3, delimiter = "\n", backward = false } = options;
33
31
  if (!filepath) throw new Error("filepath required");
34
32
  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();
37
- let fd = nativePager.open(filepath, pageSize, delimiter, backward);
33
+ if (delimiter?.length > 1) throw new RangeError("native reader only supports single-character delimiters");
34
+ const nativeReader = loadNativeAddon();
35
+ if (process.env.PAGER_TEST_CLEANUPS) {
36
+ globalThis.__pager_test_cleanups__ ??= [];
37
+ globalThis.__pager_test_cleanups__.push(nativeReader.close);
38
+ }
39
+ let fd = nativeReader.open(filepath, pageSize, delimiter, backward);
38
40
  let closed = false;
39
- const next = async () => {
41
+ async function next() {
40
42
  if (closed || !fd) return null;
41
- const data = await nativePager.next(fd);
43
+ const data = await nativeReader.next(fd);
42
44
  if (!data) return null;
43
45
  return data.toString("utf8").split(delimiter);
44
- };
45
- const nextSync = () => {
46
+ }
47
+ function nextSync() {
46
48
  if (closed || !fd) return null;
47
- const data = nativePager.nextSync(fd);
49
+ const data = nativeReader.nextSync(fd);
48
50
  if (!data) return null;
49
51
  return data.toString("utf8").split(delimiter);
50
- };
51
- const close = async () => {
52
- if (closed) return;
52
+ }
53
+ async function close() {
54
+ if (closed || !fd) return;
53
55
  closed = true;
54
56
  if (fd) {
55
57
  try {
56
- await nativePager.close(fd);
58
+ await nativeReader.close(fd);
57
59
  } catch {}
58
60
  fd = null;
59
61
  }
60
- };
62
+ }
61
63
  function tryClose() {
62
64
  close().catch(() => {});
63
65
  }
package/dist/worker.cjs CHANGED
@@ -4,10 +4,10 @@ let node_worker_threads = require("node:worker_threads");
4
4
  const { filepath, options } = node_worker_threads.workerData;
5
5
  const { chunkSize, pageSize, delimiter } = options;
6
6
  const backpressure = pageSize * 8;
7
- const post = (msg) => {
7
+ function post(msg) {
8
8
  if (!node_worker_threads.parentPort) process.exit(1);
9
9
  node_worker_threads.parentPort.postMessage(msg);
10
- };
10
+ }
11
11
  (async () => {
12
12
  try {
13
13
  const fd = await (0, node_fs_promises.open)(filepath, "r");
package/dist/worker.mjs CHANGED
@@ -4,10 +4,10 @@ import { parentPort, workerData } from "node:worker_threads";
4
4
  const { filepath, options } = workerData;
5
5
  const { chunkSize, pageSize, delimiter } = options;
6
6
  const backpressure = pageSize * 8;
7
- const post = (msg) => {
7
+ function post(msg) {
8
8
  if (!parentPort) process.exit(1);
9
9
  parentPort.postMessage(msg);
10
- };
10
+ }
11
11
  (async () => {
12
12
  try {
13
13
  const fd = await open(filepath, "r");
package/package.json CHANGED
@@ -1,13 +1,12 @@
1
1
  {
2
2
  "name": "readline-pager",
3
- "version": "0.6.2",
3
+ "version": "0.6.5",
4
4
  "scripts": {
5
5
  "build:js": "tsdown",
6
6
  "build:native": "node-gyp rebuild",
7
7
  "build": "npm run build:native && npm run build:js",
8
- "pkg:native": "node scripts/package-native.ts",
9
8
  "pretest": "npm run build",
10
- "test": "TEST_CLEANUPS=1 node --test --experimental-test-coverage test/**/*.test.ts",
9
+ "test": "PAGER_TEST_CLEANUPS=1 node --test --experimental-test-coverage test/**/*.test.ts",
11
10
  "prepublishOnly": "npm run build && npm run test",
12
11
  "benchmark:node": "node test/benchmark.ts",
13
12
  "benchmark:deno": "deno --allow-write --allow-read --allow-env test/benchmark.ts",
@@ -24,10 +23,10 @@
24
23
  "typescript": "~6.0.2"
25
24
  },
26
25
  "optionalDependencies": {
27
- "@devmor-j/readline-pager-linux-arm64": "0.6.2",
28
- "@devmor-j/readline-pager-linux-musl-arm64": "0.6.2",
29
- "@devmor-j/readline-pager-linux-musl-x64": "0.6.2",
30
- "@devmor-j/readline-pager-linux-x64": "0.6.2"
26
+ "@devmor-j/readline-pager-linux-arm64": "0.6.5",
27
+ "@devmor-j/readline-pager-linux-musl-arm64": "0.6.5",
28
+ "@devmor-j/readline-pager-linux-musl-x64": "0.6.5",
29
+ "@devmor-j/readline-pager-linux-x64": "0.6.5"
31
30
  },
32
31
  "gypfile": false,
33
32
  "type": "module",