strtok3 10.3.5 → 10.4.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/lib/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import type { Readable } from 'node:stream';
2
- import type { ReadStreamTokenizer } from './ReadStreamTokenizer.js';
3
2
  import { type ITokenizerOptions } from './core.js';
4
- import { FileTokenizer } from "./FileTokenizer.js";
5
- export { FileTokenizer } from './FileTokenizer.js';
3
+ import { FileTokenizer } from './FileTokenizer.js';
4
+ import type { ReadStreamTokenizer } from './ReadStreamTokenizer.js';
5
+ export type { IGetToken, IToken } from '@tokenizer/token';
6
6
  export * from './core.js';
7
- export type { IToken, IGetToken } from '@tokenizer/token';
7
+ export { FileTokenizer } from './FileTokenizer.js';
8
8
  /**
9
9
  * Construct ReadStreamTokenizer from given Stream.
10
10
  * Will set fileSize, if provided given Stream has set the .path property.
package/lib/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { stat as fsStat } from 'node:fs/promises';
2
2
  import { fromStream as coreFromStream } from './core.js';
3
- import { FileTokenizer } from "./FileTokenizer.js";
4
- export { FileTokenizer } from './FileTokenizer.js';
3
+ import { FileTokenizer } from './FileTokenizer.js';
5
4
  export * from './core.js';
5
+ export { FileTokenizer } from './FileTokenizer.js';
6
6
  /**
7
7
  * Construct ReadStreamTokenizer from given Stream.
8
8
  * Will set fileSize, if provided given Stream has set the .path property.
@@ -1,4 +1,4 @@
1
- import { EndOfStreamError, AbortError } from "./Errors.js";
1
+ import { AbortError, EndOfStreamError } from './Errors.js';
2
2
  export class AbstractStreamReader {
3
3
  constructor() {
4
4
  this.endOfStream = false;
@@ -38,8 +38,9 @@ export class AbstractStreamReader {
38
38
  // consume peeked data first
39
39
  while (this.peekQueue.length > 0 && remaining > 0) {
40
40
  const peekData = this.peekQueue.pop(); // Front of queue
41
- if (!peekData)
41
+ if (!peekData) {
42
42
  throw new Error('peekData should be defined');
43
+ }
43
44
  const lenCopy = Math.min(peekData.length, remaining);
44
45
  buffer.set(peekData.subarray(0, lenCopy), bytesRead);
45
46
  bytesRead += lenCopy;
@@ -59,8 +60,9 @@ export class AbstractStreamReader {
59
60
  throw new AbortError();
60
61
  }
61
62
  const chunkLen = await this.readFromStream(buffer.subarray(bytesRead), mayBeLess);
62
- if (chunkLen === 0)
63
+ if (chunkLen === 0) {
63
64
  break;
65
+ }
64
66
  bytesRead += chunkLen;
65
67
  }
66
68
  if (!mayBeLess && bytesRead < buffer.length) {
@@ -5,12 +5,12 @@ export const defaultMessages = 'End-Of-Stream';
5
5
  export class EndOfStreamError extends Error {
6
6
  constructor() {
7
7
  super(defaultMessages);
8
- this.name = "EndOfStreamError";
8
+ this.name = 'EndOfStreamError';
9
9
  }
10
10
  }
11
11
  export class AbortError extends Error {
12
- constructor(message = "The operation was aborted") {
12
+ constructor(message = 'The operation was aborted') {
13
13
  super(message);
14
- this.name = "AbortError";
14
+ this.name = 'AbortError';
15
15
  }
16
16
  }
@@ -1,5 +1,5 @@
1
1
  import type { Readable } from 'node:stream';
2
- import { AbstractStreamReader } from "./AbstractStreamReader.js";
2
+ import { AbstractStreamReader } from './AbstractStreamReader.js';
3
3
  /**
4
4
  * Node.js Readable Stream Reader
5
5
  * Ref: https://nodejs.org/api/stream.html#readable-streams
@@ -7,9 +7,9 @@ import { AbstractStreamReader } from "./AbstractStreamReader.js";
7
7
  export declare class StreamReader extends AbstractStreamReader {
8
8
  private s;
9
9
  /**
10
- * Deferred used for postponed read request (as not data is yet available to read)
10
+ * Pending requests waiting for data, tracked until completion or cancellation
11
11
  */
12
- private deferred;
12
+ private pendingRequests;
13
13
  constructor(s: Readable);
14
14
  /**
15
15
  * Read chunk from stream
@@ -23,6 +23,7 @@ export declare class StreamReader extends AbstractStreamReader {
23
23
  * @param request Deferred read request
24
24
  */
25
25
  private readDeferred;
26
+ private removeRequest;
26
27
  private reject;
27
28
  abort(): Promise<void>;
28
29
  close(): Promise<void>;
@@ -1,6 +1,6 @@
1
- import { AbortError, } from './Errors.js';
1
+ import { AbstractStreamReader } from './AbstractStreamReader.js';
2
2
  import { Deferred } from './Deferred.js';
3
- import { AbstractStreamReader } from "./AbstractStreamReader.js";
3
+ import { AbortError } from './Errors.js';
4
4
  /**
5
5
  * Node.js Readable Stream Reader
6
6
  * Ref: https://nodejs.org/api/stream.html#readable-streams
@@ -10,20 +10,26 @@ export class StreamReader extends AbstractStreamReader {
10
10
  super();
11
11
  this.s = s;
12
12
  /**
13
- * Deferred used for postponed read request (as not data is yet available to read)
13
+ * Pending requests waiting for data, tracked until completion or cancellation
14
14
  */
15
- this.deferred = null;
15
+ this.pendingRequests = new Set();
16
16
  if (!s.read || !s.once) {
17
17
  throw new Error('Expected an instance of stream.Readable');
18
18
  }
19
19
  this.s.once('end', () => {
20
20
  this.endOfStream = true;
21
- if (this.deferred) {
22
- this.deferred.resolve(0);
21
+ for (const request of this.pendingRequests) {
22
+ this.removeRequest(request);
23
+ request.deferred.resolve(0);
23
24
  }
24
25
  });
25
26
  this.s.once('error', err => this.reject(err));
26
- this.s.once('close', () => this.abort());
27
+ this.s.once('close', () => {
28
+ // Normal EOF may leave peeked bytes that the caller still needs to consume.
29
+ if (!this.endOfStream) {
30
+ void this.abort();
31
+ }
32
+ });
27
33
  }
28
34
  /**
29
35
  * Read chunk from stream
@@ -32,8 +38,9 @@ export class StreamReader extends AbstractStreamReader {
32
38
  * @returns Number of bytes read
33
39
  */
34
40
  async readFromStream(buffer, mayBeLess) {
35
- if (buffer.length === 0)
41
+ if (buffer.length === 0) {
36
42
  return 0;
43
+ }
37
44
  const readBuffer = this.s.read(buffer.length);
38
45
  if (readBuffer) {
39
46
  buffer.set(readBuffer);
@@ -42,12 +49,11 @@ export class StreamReader extends AbstractStreamReader {
42
49
  const request = {
43
50
  buffer,
44
51
  mayBeLess,
45
- deferred: new Deferred()
52
+ deferred: new Deferred(),
53
+ onReadable: () => this.readDeferred(request)
46
54
  };
47
- this.deferred = request.deferred;
48
- this.s.once('readable', () => {
49
- this.readDeferred(request);
50
- });
55
+ this.pendingRequests.add(request);
56
+ this.s.once('readable', request.onReadable);
51
57
  return request.deferred.promise;
52
58
  }
53
59
  /**
@@ -55,23 +61,38 @@ export class StreamReader extends AbstractStreamReader {
55
61
  * @param request Deferred read request
56
62
  */
57
63
  readDeferred(request) {
58
- const readBuffer = this.s.read(request.buffer.length);
59
- if (readBuffer) {
60
- request.buffer.set(readBuffer);
61
- request.deferred.resolve(readBuffer.length);
62
- this.deferred = null;
64
+ if (this.interrupted || !this.pendingRequests.has(request)) {
65
+ return;
63
66
  }
64
- else {
65
- this.s.once('readable', () => {
66
- this.readDeferred(request);
67
- });
67
+ try {
68
+ const readBuffer = this.s.read(request.buffer.length);
69
+ // Reading may synchronously emit an error or close event that cancels the request.
70
+ if (!this.pendingRequests.has(request)) {
71
+ return;
72
+ }
73
+ if (readBuffer) {
74
+ request.buffer.set(readBuffer);
75
+ this.removeRequest(request);
76
+ request.deferred.resolve(readBuffer.length);
77
+ }
78
+ else {
79
+ this.s.once('readable', request.onReadable);
80
+ }
68
81
  }
82
+ catch (error) {
83
+ this.reject(error instanceof Error ? error : new Error(String(error)));
84
+ }
85
+ }
86
+ removeRequest(request) {
87
+ this.s.removeListener('readable', request.onReadable);
88
+ this.pendingRequests.delete(request);
69
89
  }
70
90
  reject(err) {
71
91
  this.interrupted = true;
72
- if (this.deferred) {
73
- this.deferred.reject(err);
74
- this.deferred = null;
92
+ this.peekQueue = [];
93
+ for (const request of this.pendingRequests) {
94
+ this.removeRequest(request);
95
+ request.deferred.reject(err);
75
96
  }
76
97
  }
77
98
  async abort() {
@@ -11,10 +11,12 @@ export class WebStreamByobReader extends WebStreamReader {
11
11
  * @protected Bytes read
12
12
  */
13
13
  async readFromStream(buffer, mayBeLess) {
14
- if (buffer.length === 0)
14
+ if (buffer.length === 0) {
15
15
  return 0;
16
- // @ts-expect-error
17
- const result = await this.reader.read(new Uint8Array(buffer.length), { min: mayBeLess ? undefined : buffer.length });
16
+ }
17
+ const result = await this.reader.read(new Uint8Array(buffer.length), {
18
+ min: mayBeLess ? undefined : buffer.length
19
+ });
18
20
  if (result.done) {
19
21
  this.endOfStream = result.done;
20
22
  }
@@ -1,4 +1,4 @@
1
- import { AbstractStreamReader } from "./AbstractStreamReader.js";
1
+ import { AbstractStreamReader } from './AbstractStreamReader.js';
2
2
  export declare class WebStreamDefaultReader extends AbstractStreamReader {
3
3
  private reader;
4
4
  private buffer;
@@ -1,5 +1,5 @@
1
+ import { AbstractStreamReader } from './AbstractStreamReader.js';
1
2
  import { EndOfStreamError } from './Errors.js';
2
- import { AbstractStreamReader } from "./AbstractStreamReader.js";
3
3
  export class WebStreamDefaultReader extends AbstractStreamReader {
4
4
  constructor(reader) {
5
5
  super();
@@ -28,8 +28,9 @@ export class WebStreamDefaultReader extends AbstractStreamReader {
28
28
  * @protected Bytes read
29
29
  */
30
30
  async readFromStream(buffer, mayBeLess) {
31
- if (buffer.length === 0)
31
+ if (buffer.length === 0) {
32
32
  return 0;
33
+ }
33
34
  let totalBytesRead = 0;
34
35
  // Serve from the internal buffer first
35
36
  if (this.buffer) {
@@ -56,7 +57,11 @@ export class WebStreamDefaultReader extends AbstractStreamReader {
56
57
  return this.reader.cancel();
57
58
  }
58
59
  async close() {
59
- await this.abort();
60
- this.reader.releaseLock();
60
+ try {
61
+ await this.abort();
62
+ }
63
+ finally {
64
+ this.reader.releaseLock();
65
+ }
61
66
  }
62
67
  }
@@ -1,4 +1,4 @@
1
- import { AbstractStreamReader } from "./AbstractStreamReader.js";
1
+ import { AbstractStreamReader } from './AbstractStreamReader.js';
2
2
  export declare abstract class WebStreamReader extends AbstractStreamReader {
3
3
  protected reader: ReadableStreamDefaultReader | ReadableStreamBYOBReader;
4
4
  constructor(reader: ReadableStreamDefaultReader | ReadableStreamBYOBReader);
@@ -1,4 +1,4 @@
1
- import { AbstractStreamReader } from "./AbstractStreamReader.js";
1
+ import { AbstractStreamReader } from './AbstractStreamReader.js';
2
2
  export class WebStreamReader extends AbstractStreamReader {
3
3
  constructor(reader) {
4
4
  super();
@@ -2,7 +2,7 @@ import { WebStreamByobReader } from './WebStreamByobReader.js';
2
2
  import { WebStreamDefaultReader } from './WebStreamDefaultReader.js';
3
3
  export function makeWebStreamReader(stream) {
4
4
  try {
5
- const reader = stream.getReader({ mode: "byob" });
5
+ const reader = stream.getReader({ mode: 'byob' });
6
6
  if (reader instanceof ReadableStreamDefaultReader) {
7
7
  // Fallback to default reader in case `mode: byob` is ignored
8
8
  return new WebStreamDefaultReader(reader);
@@ -1,6 +1,6 @@
1
+ export type { IStreamReader } from './AbstractStreamReader.js';
1
2
  export { AbortError, EndOfStreamError } from './Errors.js';
2
3
  export { StreamReader } from './StreamReader.js';
3
4
  export { WebStreamByobReader } from './WebStreamByobReader.js';
4
5
  export { WebStreamDefaultReader } from './WebStreamDefaultReader.js';
5
- export type { IStreamReader } from './AbstractStreamReader.js';
6
6
  export { type AnyWebByteStream, makeWebStreamReader } from './WebStreamReaderFactory.js';
package/lib/types.d.ts CHANGED
@@ -123,6 +123,13 @@ export interface ITokenizer {
123
123
  }
124
124
  export type OnClose = () => Promise<void>;
125
125
  export interface ITokenizerOptions {
126
+ /**
127
+ * Maximum bytes in a dynamically sized tokenizer buffer or stream lookahead span.
128
+ * Set once when creating the tokenizer; applies to subsequent reads and peeks.
129
+ * Disabled by default (Infinity). Must be a positive safe integer or Infinity.
130
+ * Does not limit total process memory, caller-owned buffers, or decoded token values.
131
+ */
132
+ maxBufferSize?: number;
126
133
  /**
127
134
  * Pass additional file information to the tokenizer
128
135
  */
package/package.json CHANGED
@@ -1,94 +1,95 @@
1
- {
2
- "name": "strtok3",
3
- "version": "10.3.5",
4
- "description": "A promise based streaming tokenizer",
5
- "author": {
6
- "name": "Borewit",
7
- "url": "https://github.com/Borewit"
8
- },
9
- "funding": {
10
- "type": "github",
11
- "url": "https://github.com/sponsors/Borewit"
12
- },
13
- "scripts": {
14
- "clean": "del-cli 'lib/**/*.js' 'lib/**/*.js.map' 'lib/**/*.d.ts' 'test/**/*.js' 'test/**/*.js.map'",
15
- "compile-src": "tsc -p lib --sourceMap false",
16
- "compile-test": "tsc -p test",
17
- "compile": "yarn run compile-src && yarn run compile-test",
18
- "build": "yarn run clean && yarn run compile",
19
- "prepublishOnly": "yarn run build",
20
- "eslint": "eslint lib test",
21
- "lint:md": "remark -u preset-lint-recommended .",
22
- "lint:ts": "biome check",
23
- "lint": "yarn run lint:md && yarn run lint:ts",
24
- "fix": "yarn run biome lint --write",
25
- "test": "mocha",
26
- "bun:test": "bun run --bun test",
27
- "test-coverage": "c8 yarn run test",
28
- "send-codacy": "c8 report --reporter=text-lcov | codacy-coverage",
29
- "start": "yarn run compile && yarn run lint && yarn run cover-test",
30
- "update-biome": "yarn add -D --exact @biomejs/biome && npx @biomejs/biome migrate --write"
31
- },
32
- "engines": {
33
- "node": ">=18"
34
- },
35
- "repository": {
36
- "type": "git",
37
- "url": "git+https://github.com/Borewit/strtok3.git"
38
- },
39
- "license": "MIT",
40
- "type": "module",
41
- "exports": {
42
- ".": {
43
- "node": "./lib/index.js",
44
- "default": "./lib/core.js"
45
- },
46
- "./core": "./lib/core.js"
47
- },
48
- "types": "lib/index.d.ts",
49
- "files": [
50
- "lib/**/*.js",
51
- "lib/**/*.d.ts"
52
- ],
53
- "bugs": {
54
- "url": "https://github.com/Borewit/strtok3/issues"
55
- },
56
- "dependencies": {
57
- "@tokenizer/token": "^0.3.0"
58
- },
59
- "devDependencies": {
60
- "@biomejs/biome": "2.4.8",
61
- "@types/chai": "^5.2.2",
62
- "@types/chai-as-promised": "^8.0.2",
63
- "@types/debug": "^4.1.12",
64
- "@types/mocha": "^10.0.10",
65
- "@types/node": "^24.1.0",
66
- "c8": "^11.0.0",
67
- "chai": "^5.2.1",
68
- "chai-as-promised": "^8.0.2",
69
- "del-cli": "^7.0.0",
70
- "mocha": "^11.7.5",
71
- "node-readable-to-web-readable-stream": "^0.4.2",
72
- "remark-cli": "^12.0.1",
73
- "remark-preset-lint-recommended": "^7.0.1",
74
- "token-types": "^6.1.2",
75
- "ts-node": "^10.9.2",
76
- "typescript": "^5.8.3",
77
- "uint8array-extras": "^1.4.0"
78
- },
79
- "keywords": [
80
- "tokenizer",
81
- "reader",
82
- "token",
83
- "async",
84
- "promise",
85
- "parser",
86
- "decoder",
87
- "binary",
88
- "endian",
89
- "uint",
90
- "stream",
91
- "streaming"
92
- ],
93
- "packageManager": "yarn@4.9.2"
94
- }
1
+ {
2
+ "name": "strtok3",
3
+ "version": "10.4.1",
4
+ "description": "A promise based streaming tokenizer",
5
+ "author": {
6
+ "name": "Borewit",
7
+ "url": "https://github.com/Borewit"
8
+ },
9
+ "funding": {
10
+ "type": "github",
11
+ "url": "https://github.com/sponsors/Borewit"
12
+ },
13
+ "scripts": {
14
+ "clean": "del-cli 'lib/**/*.js' 'lib/**/*.js.map' 'lib/**/*.d.ts' 'test/**/*.js' 'test/**/*.js.map'",
15
+ "compile-src": "tsc -p lib --sourceMap false",
16
+ "compile-test": "tsc -p test",
17
+ "compile": "yarn run compile-src && yarn run compile-test",
18
+ "build": "yarn run clean && yarn run compile",
19
+ "prepublishOnly": "yarn run build",
20
+ "eslint": "eslint lib test",
21
+ "lint:md": "remark -u preset-lint-recommended .",
22
+ "lint:ts": "biome check",
23
+ "lint": "yarn run lint:md && yarn run lint:ts",
24
+ "fix": "yarn run lint:ts:fix",
25
+ "test": "mocha",
26
+ "bun:test": "bun run --bun test",
27
+ "test-coverage": "c8 yarn run test",
28
+ "send-codacy": "c8 report --reporter=text-lcov | codacy-coverage",
29
+ "start": "yarn run compile && yarn run lint && yarn run cover-test",
30
+ "update-biome": "yarn add -D --exact @biomejs/biome && npx @biomejs/biome migrate --write",
31
+ "lint:ts:fix": "biome check --write"
32
+ },
33
+ "engines": {
34
+ "node": ">=18"
35
+ },
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/Borewit/strtok3.git"
39
+ },
40
+ "license": "MIT",
41
+ "type": "module",
42
+ "exports": {
43
+ ".": {
44
+ "node": "./lib/index.js",
45
+ "default": "./lib/core.js"
46
+ },
47
+ "./core": "./lib/core.js"
48
+ },
49
+ "types": "lib/index.d.ts",
50
+ "files": [
51
+ "lib/**/*.js",
52
+ "lib/**/*.d.ts"
53
+ ],
54
+ "bugs": {
55
+ "url": "https://github.com/Borewit/strtok3/issues"
56
+ },
57
+ "dependencies": {
58
+ "@tokenizer/token": "^0.3.0"
59
+ },
60
+ "devDependencies": {
61
+ "@biomejs/biome": "2.5.15",
62
+ "@types/chai": "^5.2.2",
63
+ "@types/chai-as-promised": "^8.0.2",
64
+ "@types/debug": "^4.1.12",
65
+ "@types/mocha": "^10.0.10",
66
+ "@types/node": "^24.19.1",
67
+ "c8": "^12.0.0",
68
+ "chai": "^6.3.0",
69
+ "chai-as-promised": "^8.0.2",
70
+ "del-cli": "^7.0.0",
71
+ "mocha": "^11",
72
+ "node-readable-to-web-readable-stream": "^0.4.2",
73
+ "remark-cli": "^12.0.1",
74
+ "remark-preset-lint-recommended": "^7.0.1",
75
+ "token-types": "^6.1.2",
76
+ "tsx": "^4.23.15",
77
+ "typescript": "^7.0.2",
78
+ "uint8array-extras": "^1.6.0"
79
+ },
80
+ "keywords": [
81
+ "tokenizer",
82
+ "reader",
83
+ "token",
84
+ "async",
85
+ "promise",
86
+ "parser",
87
+ "decoder",
88
+ "binary",
89
+ "endian",
90
+ "uint",
91
+ "stream",
92
+ "streaming"
93
+ ],
94
+ "packageManager": "yarn@4.18.1"
95
+ }