spliterator 1.5.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.
Files changed (75) hide show
  1. package/LICENSE.md +650 -0
  2. package/README.md +119 -0
  3. package/out/index.d.ts +21 -0
  4. package/out/index.d.ts.map +1 -0
  5. package/out/index.js +21 -0
  6. package/out/index.js.map +1 -0
  7. package/out/lib/AsyncSpliterator.d.ts +127 -0
  8. package/out/lib/AsyncSpliterator.d.ts.map +1 -0
  9. package/out/lib/AsyncSpliterator.js +332 -0
  10. package/out/lib/AsyncSpliterator.js.map +1 -0
  11. package/out/lib/BufferController.d.ts +62 -0
  12. package/out/lib/BufferController.d.ts.map +1 -0
  13. package/out/lib/BufferController.js +93 -0
  14. package/out/lib/BufferController.js.map +1 -0
  15. package/out/lib/CSVSpliterator.d.ts +104 -0
  16. package/out/lib/CSVSpliterator.d.ts.map +1 -0
  17. package/out/lib/CSVSpliterator.js +83 -0
  18. package/out/lib/CSVSpliterator.js.map +1 -0
  19. package/out/lib/CharacterSequence.d.ts +103 -0
  20. package/out/lib/CharacterSequence.d.ts.map +1 -0
  21. package/out/lib/CharacterSequence.js +184 -0
  22. package/out/lib/CharacterSequence.js.map +1 -0
  23. package/out/lib/CompositeDataView.d.ts +104 -0
  24. package/out/lib/CompositeDataView.d.ts.map +1 -0
  25. package/out/lib/CompositeDataView.js +242 -0
  26. package/out/lib/CompositeDataView.js.map +1 -0
  27. package/out/lib/DelimitedChunkReader.d.ts +67 -0
  28. package/out/lib/DelimitedChunkReader.d.ts.map +1 -0
  29. package/out/lib/DelimitedChunkReader.js +113 -0
  30. package/out/lib/DelimitedChunkReader.js.map +1 -0
  31. package/out/lib/DelimiterTransformer.d.ts +27 -0
  32. package/out/lib/DelimiterTransformer.d.ts.map +1 -0
  33. package/out/lib/DelimiterTransformer.js +26 -0
  34. package/out/lib/DelimiterTransformer.js.map +1 -0
  35. package/out/lib/IndexQueue.d.ts +48 -0
  36. package/out/lib/IndexQueue.d.ts.map +1 -0
  37. package/out/lib/IndexQueue.js +80 -0
  38. package/out/lib/IndexQueue.js.map +1 -0
  39. package/out/lib/JSONSpliterator.d.ts +19 -0
  40. package/out/lib/JSONSpliterator.d.ts.map +1 -0
  41. package/out/lib/JSONSpliterator.js +55 -0
  42. package/out/lib/JSONSpliterator.js.map +1 -0
  43. package/out/lib/SlidingWindow.d.ts +93 -0
  44. package/out/lib/SlidingWindow.d.ts.map +1 -0
  45. package/out/lib/SlidingWindow.js +176 -0
  46. package/out/lib/SlidingWindow.js.map +1 -0
  47. package/out/lib/Spliterator.d.ts +51 -0
  48. package/out/lib/Spliterator.d.ts.map +1 -0
  49. package/out/lib/Spliterator.js +238 -0
  50. package/out/lib/Spliterator.js.map +1 -0
  51. package/out/lib/TextSpliterator.d.ts +40 -0
  52. package/out/lib/TextSpliterator.d.ts.map +1 -0
  53. package/out/lib/TextSpliterator.js +56 -0
  54. package/out/lib/TextSpliterator.js.map +1 -0
  55. package/out/lib/casing.d.ts +28 -0
  56. package/out/lib/casing.d.ts.map +1 -0
  57. package/out/lib/casing.js +69 -0
  58. package/out/lib/casing.js.map +1 -0
  59. package/out/lib/node/fs.d.ts +98 -0
  60. package/out/lib/node/fs.d.ts.map +1 -0
  61. package/out/lib/node/fs.js +162 -0
  62. package/out/lib/node/fs.js.map +1 -0
  63. package/out/lib/shared.d.ts +167 -0
  64. package/out/lib/shared.d.ts.map +1 -0
  65. package/out/lib/shared.js +92 -0
  66. package/out/lib/shared.js.map +1 -0
  67. package/out/lib/take.d.ts +26 -0
  68. package/out/lib/take.d.ts.map +1 -0
  69. package/out/lib/take.js +71 -0
  70. package/out/lib/take.js.map +1 -0
  71. package/out/lib/writer.d.ts +34 -0
  72. package/out/lib/writer.d.ts.map +1 -0
  73. package/out/lib/writer.js +41 -0
  74. package/out/lib/writer.js.map +1 -0
  75. package/package.json +100 -0
package/README.md ADDED
@@ -0,0 +1,119 @@
1
+ # Ribbon 🎀
2
+
3
+ Ribbon makes newline-delimited files easy to work with.
4
+
5
+ Let's say you have a huge newline-delimited JSON file that can't fit into memory.
6
+
7
+ ```js
8
+ {"name": "Jessie", "age": 30}
9
+ {"name": "Kelly", "age": 40}
10
+ {"name": "Loren", "age": 50}
11
+ // Several hundred thousand more lines...
12
+ ```
13
+
14
+ Ribbon can help you read it line-by-line:
15
+
16
+ ```ts
17
+ import { JSONSpliterator } from "spliterator"
18
+
19
+ interface Person {
20
+ name: string
21
+ age: number
22
+ }
23
+
24
+ const reader = JSONSpliterator.fromAsync("example.jsonl")
25
+
26
+ for await (const line of reader) {
27
+ console.log(line) // {"name": "Alice", "age": 30}, etc.
28
+ }
29
+ ```
30
+
31
+ [![NPM Version](https://img.shields.io/npm/v/%40sister.software%2Fribbon)](https://www.npmjs.com/package/spliterator)
32
+
33
+ # Installation
34
+
35
+ ```bash
36
+ yarn add spliterator
37
+ # or
38
+ npm install spliterator
39
+ ```
40
+
41
+ # Usage
42
+
43
+ ## Character-delimited files
44
+
45
+ While Ribbon supports any delimited byte stream, it's particularly useful for character-delimited content such as comma-separated values (CSV), tab-separated values (TSV) – or any other delimiter you can think of.
46
+
47
+ ```csv
48
+ Full Name, Occupation, Age
49
+ Morgan, Developer, 30
50
+ Nataly, Designer, 40
51
+ Orlando, Manager, 50
52
+ ```
53
+
54
+ ```ts
55
+ import { CSVSpliterator } from "spliterator"
56
+
57
+ const reader = CSVSpliterator.fromAsync("people.csv")
58
+
59
+ for await (const columns of reader) {
60
+ console.log(columns) // ["Full Name", "Occupation", "Age"], ["Morgan", "Developer", 30], etc.
61
+ }
62
+ ```
63
+
64
+ CSV files can also be emitted as objects with headers as keys, with some quality-of-life features, such as normalizing property keys:
65
+
66
+ ```ts
67
+ import { CSVSpliterator } from "spliterator"
68
+
69
+ interface Person {
70
+ full_name: string
71
+ occupation: string
72
+ age: number
73
+ }
74
+
75
+ const reader = CSVSpliterator.fromAsync<Person>("people.csv", { mode: "object" })
76
+
77
+ for await (const columns of reader) {
78
+ console.log(columns) // { full_name: "Morgan", occupation: "Developer", age: 30 }, etc.
79
+ }
80
+ ```
81
+
82
+ ## Advanced usage
83
+
84
+ Ribbon is designed to be simple to use, but also flexible and powerful.
85
+ For more advanced use cases, check out our tests in the `test` directory, or our fully-annotated source code.
86
+
87
+ ### Reading from a stream
88
+
89
+ All Ribbon generators implement the `Generator` and `AsyncGenerator` interfaces, so you can use them in `for...of` and `for await...of` loops, as well the web-native [ReadableStreams](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream), so you can use them in `for await...of` loops, as well as piping them through transformations to avoid nested and partially materialized streams.
90
+
91
+ ```ts
92
+ import { JSONSpliterator } from "spliterator"
93
+
94
+ const people = [
95
+ { name: "Alice", age: 30 },
96
+ { name: "Bob", age: 40 },
97
+ { name: "Charlie", age: 50 },
98
+ ]
99
+
100
+ const generator = JSONSpliterator.from(people.map(JSON.stringify).join("\n"))
101
+ const stream = ReadableStream.from(generator)
102
+
103
+ for await (const line of stream) {
104
+ console.log(line) // {"name": "Alice", "age": 30}, etc.
105
+ }
106
+ ```
107
+
108
+ ### Custom generators
109
+
110
+ While Ribbon includes premade exports for most use-cases, custom generators can be created via `DelimitedGenerator`. This class is a low-level interface that allows you to create your own generators for any kind of delimited content.
111
+
112
+ # License
113
+
114
+ Ribbon is licensed under the AGPL-3.0 license. Generally,
115
+ this means that you can use the software for free, but you must share
116
+ any modifications you make to the software.
117
+
118
+ For more information on commercial usage licensing, please contact us at
119
+ `hello@sister.software`
package/out/index.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ */
6
+ export * from "./lib/BufferController.js";
7
+ export * from "./lib/casing.js";
8
+ export * from "./lib/CharacterSequence.js";
9
+ export * from "./lib/CompositeDataView.js";
10
+ export * from "./lib/CSVSpliterator.js";
11
+ export * from "./lib/DelimitedChunkReader.js";
12
+ export * from "./lib/DelimiterTransformer.js";
13
+ export * from "./lib/IndexQueue.js";
14
+ export * from "./lib/JSONSpliterator.js";
15
+ export * from "./lib/shared.js";
16
+ export * from "./lib/SlidingWindow.js";
17
+ export * from "./lib/Spliterator.js";
18
+ export * from "./lib/take.js";
19
+ export * from "./lib/TextSpliterator.js";
20
+ export * from "./lib/writer.js";
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,2BAA2B,CAAA;AACzC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,4BAA4B,CAAA;AAC1C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,yBAAyB,CAAA;AACvC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,+BAA+B,CAAA;AAC7C,cAAc,qBAAqB,CAAA;AACnC,cAAc,0BAA0B,CAAA;AACxC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,wBAAwB,CAAA;AACtC,cAAc,sBAAsB,CAAA;AACpC,cAAc,eAAe,CAAA;AAC7B,cAAc,0BAA0B,CAAA;AACxC,cAAc,iBAAiB,CAAA"}
package/out/index.js ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ */
6
+ export * from "./lib/BufferController.js";
7
+ export * from "./lib/casing.js";
8
+ export * from "./lib/CharacterSequence.js";
9
+ export * from "./lib/CompositeDataView.js";
10
+ export * from "./lib/CSVSpliterator.js";
11
+ export * from "./lib/DelimitedChunkReader.js";
12
+ export * from "./lib/DelimiterTransformer.js";
13
+ export * from "./lib/IndexQueue.js";
14
+ export * from "./lib/JSONSpliterator.js";
15
+ export * from "./lib/shared.js";
16
+ export * from "./lib/SlidingWindow.js";
17
+ export * from "./lib/Spliterator.js";
18
+ export * from "./lib/take.js";
19
+ export * from "./lib/TextSpliterator.js";
20
+ export * from "./lib/writer.js";
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,2BAA2B,CAAA;AACzC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,4BAA4B,CAAA;AAC1C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,yBAAyB,CAAA;AACvC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,+BAA+B,CAAA;AAC7C,cAAc,qBAAqB,CAAA;AACnC,cAAc,0BAA0B,CAAA;AACxC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,wBAAwB,CAAA;AACtC,cAAc,sBAAsB,CAAA;AACpC,cAAc,eAAe,CAAA;AAC7B,cAAc,0BAA0B,CAAA;AACxC,cAAc,iBAAiB,CAAA"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ */
6
+ import { CharacterSequenceInput } from "./CharacterSequence.js";
7
+ import { AsyncDataResource, type FileResourceLike } from "./shared.js";
8
+ /**
9
+ * Initialization options for creating a spliterator.
10
+ */
11
+ export interface SpliteratorInit {
12
+ /**
13
+ * The character to delimit by. Typically a newline or comma.
14
+ */
15
+ delimiter?: CharacterSequenceInput;
16
+ /**
17
+ * The byte offset to start reading from.
18
+ *
19
+ * This is an advanced option that is not typically used.
20
+ *
21
+ * @default 0
22
+ */
23
+ position?: number;
24
+ /**
25
+ * Whether to emit repeated delimiters as empty buffers.
26
+ *
27
+ * Setting this to `false` matches the behavior of `String.prototype.split`.
28
+ *
29
+ * @default true
30
+ */
31
+ skipEmpty?: boolean;
32
+ /**
33
+ * Count of skipped matches before emitting a data.
34
+ *
35
+ * @default 0
36
+ */
37
+ drop?: number;
38
+ /**
39
+ * The maximum number of data slices to yield.
40
+ *
41
+ * Useful for limiting the number of emitted slices, i.e. lines in a file.
42
+ *
43
+ * Note that skipped slices are not counted towards the limit.
44
+ *
45
+ * @default Infinity
46
+ */
47
+ take?: number;
48
+ /**
49
+ * Whether to emit debug information.
50
+ */
51
+ debug?: boolean;
52
+ }
53
+ /**
54
+ * Initialization options for creating an asynchronous spliterator.
55
+ */
56
+ export interface AsyncSpliteratorInit extends SpliteratorInit {
57
+ /**
58
+ * The buffer chunk size to read from the file, i.e. the high-water mark for the file read
59
+ * operation.
60
+ *
61
+ * @default BlockSize * 16
62
+ * @minimum The delimiter byte length * 4 or block size of the file system. Whichever is greater.
63
+ * @maximum The byte length of the file.
64
+ */
65
+ highWaterMark?: number;
66
+ /**
67
+ * Whether to close the file handle after completion.
68
+ *
69
+ * @default true
70
+ */
71
+ autoClose?: boolean;
72
+ }
73
+ /**
74
+ * An asynchronous spliterator for reading delimited byte streams.
75
+ *
76
+ * ```ts
77
+ * import { AsyncSpliterator } from "spliterator"
78
+ *
79
+ * const file = await AsyncSpliterator.from("data.csv")
80
+ *
81
+ * for await (const line of file) {
82
+ * console.log(line)
83
+ * }
84
+ * ```
85
+ *
86
+ * @see {@linkcode Spliterator} for the synchronous version.
87
+ */
88
+ export declare class AsyncSpliterator implements AsyncIterableIterator<Uint8Array>, AsyncDisposable {
89
+ #private;
90
+ /**
91
+ * Create a new delimited generator from a data resource.
92
+ *
93
+ * Unlike the constructor, this method can be used to create a generator from a file path or URL.
94
+ *
95
+ * @param source - The data resource to read from.
96
+ * @param init - The initialization options for the generator.
97
+ */
98
+ static from(source: AsyncDataResource, init?: AsyncSpliteratorInit): Promise<AsyncSpliterator>;
99
+ /**
100
+ * Dispose of the spliterator, closing the file handle if necessary.
101
+ */
102
+ [Symbol.asyncDispose](): Promise<void>;
103
+ /**
104
+ * Create a new delimited generator from a file handle.
105
+ *
106
+ * @param file - The file to read from.
107
+ * @param init - The initialization options for the generator.
108
+ * @see {@linkcode AsyncSpliterator.from} to create a new generator from a data resource.
109
+ */
110
+ constructor(file: FileResourceLike, init?: AsyncSpliteratorInit);
111
+ next(): Promise<IteratorResult<Uint8Array>>;
112
+ /**
113
+ * Collect all the byte ranges from the file.
114
+ *
115
+ * **This method will read the entire file into memory.**
116
+ */
117
+ toArray(): Promise<Uint8Array[]>;
118
+ /**
119
+ * Collect all the byte ranges from the file as a string.
120
+ *
121
+ * **This method will read the entire file into memory.**
122
+ */
123
+ toDecodedArray(decoder?: import("util").TextDecoder): Promise<string[]>;
124
+ [Symbol.asyncIterator](): this;
125
+ return(): Promise<IteratorReturnResult<undefined>>;
126
+ }
127
+ //# sourceMappingURL=AsyncSpliterator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AsyncSpliterator.d.ts","sourceRoot":"","sources":["../../lib/AsyncSpliterator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAqB,sBAAsB,EAAE,MAAM,wBAAwB,CAAA;AAElF,OAAO,EAEN,iBAAiB,EAGjB,KAAK,gBAAgB,EAErB,MAAM,aAAa,CAAA;AAEpB;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B;;OAEG;IACH,SAAS,CAAC,EAAE,sBAAsB,CAAA;IAElC;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IAEb;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IAEb;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;CACf;AAED;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,eAAe;IAC5D;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IAEtB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;CACnB;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,gBAAiB,YAAW,qBAAqB,CAAC,UAAU,CAAC,EAAE,eAAe;;IAG1F;;;;;;;OAOG;WACU,IAAI,CAAC,MAAM,EAAE,iBAAiB,EAAE,IAAI,GAAE,oBAAyB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAaxG;;OAEG;IACU,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC;IASnD;;;;;;OAMG;gBAES,IAAI,EAAE,gBAAgB,EAAE,IAAI,GAAE,oBAAyB;IA+RtD,IAAI,IAAI,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IAgCxD;;;;OAIG;IACI,OAAO,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAIvC;;;;OAIG;IACI,cAAc,CAAC,OAAO,6BAAoB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAI9D,CAAC,MAAM,CAAC,aAAa,CAAC;IAItB,MAAM,IAAI,OAAO,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAAC;CAGzD"}
@@ -0,0 +1,332 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ */
6
+ import { BufferController } from "./BufferController.js";
7
+ import { CharacterSequence } from "./CharacterSequence.js";
8
+ import { IndexQueue } from "./IndexQueue.js";
9
+ import { applyReaderPolyfill, isFileResourceLike, } from "./shared.js";
10
+ /**
11
+ * An asynchronous spliterator for reading delimited byte streams.
12
+ *
13
+ * ```ts
14
+ * import { AsyncSpliterator } from "spliterator"
15
+ *
16
+ * const file = await AsyncSpliterator.from("data.csv")
17
+ *
18
+ * for await (const line of file) {
19
+ * console.log(line)
20
+ * }
21
+ * ```
22
+ *
23
+ * @see {@linkcode Spliterator} for the synchronous version.
24
+ */
25
+ export class AsyncSpliterator {
26
+ //#region Lifecycle
27
+ /**
28
+ * Create a new delimited generator from a data resource.
29
+ *
30
+ * Unlike the constructor, this method can be used to create a generator from a file path or URL.
31
+ *
32
+ * @param source - The data resource to read from.
33
+ * @param init - The initialization options for the generator.
34
+ */
35
+ static async from(source, init = {}) {
36
+ let file;
37
+ if (isFileResourceLike(source)) {
38
+ file = source;
39
+ }
40
+ else {
41
+ const { NodeFileResource } = await import("spliterator/node/fs");
42
+ file = await NodeFileResource.open(source);
43
+ }
44
+ return new AsyncSpliterator(file, init);
45
+ }
46
+ /**
47
+ * Dispose of the spliterator, closing the file handle if necessary.
48
+ */
49
+ async [Symbol.asyncDispose]() {
50
+ this.#indices.clear();
51
+ this.#controller.clear();
52
+ if (this.#autoClose) {
53
+ await this.#file[Symbol.asyncDispose]?.();
54
+ }
55
+ }
56
+ /**
57
+ * Create a new delimited generator from a file handle.
58
+ *
59
+ * @param file - The file to read from.
60
+ * @param init - The initialization options for the generator.
61
+ * @see {@linkcode AsyncSpliterator.from} to create a new generator from a data resource.
62
+ */
63
+ constructor(file, init = {}) {
64
+ applyReaderPolyfill(file);
65
+ this.#file = file;
66
+ this.#autoClose = init.autoClose ?? false;
67
+ this.#needle = new CharacterSequence(init.delimiter);
68
+ this.#readPosition = init.position ?? 0;
69
+ this.#totalByteSize = file.size;
70
+ this.#yieldByteEstimate = this.#totalByteSize - this.#readPosition;
71
+ this.#highWaterMark = Math.max(this.#needle.length * 4, init.highWaterMark ?? 4096);
72
+ this.#yieldDropCount = Math.max(0, init.drop ?? 0);
73
+ this.#yieldStopCount = Math.max(init.take ?? Infinity, 0) + this.#yieldDropCount;
74
+ this.#skipEmpty = init.skipEmpty ?? true;
75
+ this.#controller = new BufferController({
76
+ initialBufferSize: Math.max(this.#needle.length * 4, this.#highWaterMark),
77
+ });
78
+ this.#debug = init.debug ?? false;
79
+ this.#log = this.#debug ? console.debug.bind(console) : () => void 0;
80
+ }
81
+ //#endregion
82
+ //#region Private Properties
83
+ /**
84
+ * The file to read from.
85
+ */
86
+ #file;
87
+ /**
88
+ * Whether to close the file handle when the iterator is completed or disposed.
89
+ */
90
+ #autoClose;
91
+ /**
92
+ * A queue of index tuples marking the start and end of delimiter positions.
93
+ *
94
+ * Note that indices are relative to the buffer, not the file.
95
+ *
96
+ * This means that the start index is always 0, and the end index is the byte length of the
97
+ * buffer.
98
+ */
99
+ #indices = new IndexQueue();
100
+ /**
101
+ * The byte sequence to search for, i.e. an encoded delimiter.
102
+ */
103
+ #needle;
104
+ /**
105
+ * The buffer containing the current chunks of data. This will be resized as needed to accommodate
106
+ * the file read operation.
107
+ */
108
+ #controller;
109
+ /**
110
+ * The total byte size of the file.
111
+ */
112
+ #totalByteSize;
113
+ /**
114
+ * The total number of bytes we expect to yield.
115
+ *
116
+ * We use this to ensure that we don't miss any data when the file is read in chunks.
117
+ */
118
+ #yieldByteEstimate;
119
+ /**
120
+ * How many yields to skip.
121
+ */
122
+ #yieldDropCount;
123
+ /**
124
+ * How many yields to allow before stopping.
125
+ */
126
+ #yieldStopCount;
127
+ /**
128
+ * Whether to skip empty yields.
129
+ */
130
+ #skipEmpty;
131
+ /**
132
+ * The high water mark for the buffer.
133
+ *
134
+ * This defines the size of each read operation, as well as the total size of indices to keep in
135
+ * memory.
136
+ */
137
+ #highWaterMark;
138
+ /**
139
+ * The total number of bytes we've yielded.
140
+ */
141
+ #yieldedByteLength = 0;
142
+ /**
143
+ * The total number of yields.
144
+ */
145
+ #yieldCount = 0;
146
+ /**
147
+ * The current byte index to perform read operations from.
148
+ */
149
+ #readPosition;
150
+ /**
151
+ * The last byte range seen while draining the buffer.
152
+ */
153
+ #lastByteRangeSeen;
154
+ /**
155
+ * Whether to output debug information.
156
+ */
157
+ #debug;
158
+ /**
159
+ * Whether the iterator is done.
160
+ */
161
+ #done = false;
162
+ //#endregion
163
+ //#region Private Methods
164
+ #log;
165
+ /**
166
+ * Find and enqueue delimiter positions.
167
+ */
168
+ #search() {
169
+ const lastByteRange = this.#indices.peekLast();
170
+ let searchCursor = lastByteRange ? lastByteRange[1] + this.#needle.length : 0;
171
+ while (searchCursor <= this.#controller.bytesWritten) {
172
+ const delimiterIndex = this.#needle.search(this.#controller.bytes, searchCursor);
173
+ if (delimiterIndex === -1) {
174
+ this.#log(`No viable byte range found in buffer. Breaking.`);
175
+ break;
176
+ }
177
+ this.#log("Found byte range", [searchCursor, delimiterIndex]);
178
+ this.#indices.enqueue([searchCursor, delimiterIndex]);
179
+ searchCursor = delimiterIndex + this.#needle.length;
180
+ }
181
+ }
182
+ /**
183
+ * Read a chunk of data from the file.
184
+ */
185
+ async #read() {
186
+ // We're extra careful here to ensure that we don't read past the end of the file.
187
+ // And because `file.read` doesn't expose the number of bytes read,
188
+ // we keep track of this ourselves.
189
+ const nextReadLength = Math.min(this.#highWaterMark, this.#totalByteSize - this.#readPosition);
190
+ // Offset in this context means the byte offset to begin writing to the buffer.
191
+ const offset = this.#controller.bytesWritten;
192
+ // Before reading we grow the buffer to ensure that we have enough space.
193
+ const nextBufferSize = Math.max(this.#controller.byteLengthMinimum, offset + nextReadLength);
194
+ this.#controller.grow(nextBufferSize);
195
+ this.#log("Before read", { cursor: this.#readPosition, nextReadLength, nextBufferSize, offset });
196
+ await this.#file.read({
197
+ buffer: this.#controller.bytes,
198
+ offset,
199
+ position: this.#readPosition,
200
+ length: nextReadLength,
201
+ });
202
+ this.#controller.bytesWritten += nextReadLength;
203
+ // this.#log(
204
+ // "Inspecting buffer",
205
+ // debugAsVisibleCharacters(this.#controller.bytes.subarray(0, this.#controller.bytesWritten))
206
+ // )
207
+ this.#readPosition += nextReadLength;
208
+ }
209
+ /**
210
+ * Fill the buffer with data and search for delimiters.
211
+ */
212
+ async #fill() {
213
+ if (this.#readPosition === this.#totalByteSize) {
214
+ this.#log("Reached end of file. Preparing to finalize.");
215
+ // There's a few special cases we could get this far and not have drained the buffer.
216
+ const lastByteRange = this.#lastByteRangeSeen;
217
+ if (lastByteRange) {
218
+ const lastByteIndex = lastByteRange[1];
219
+ // There's a special case where the last delimiter is at the end of the *file*.
220
+ if (lastByteIndex < this.#controller.bytesWritten) {
221
+ // We need to determine if we're at the end of the *file* and there's no delimiter.
222
+ const possibleDelimiterIndex = this.#needle.search(this.#controller.bytes, this.#controller.bytesWritten - this.#needle.length);
223
+ if (possibleDelimiterIndex !== -1) {
224
+ this.#log("Inserted byte range at the last delimiter", [
225
+ possibleDelimiterIndex,
226
+ this.#controller.bytesWritten,
227
+ ]);
228
+ // We found a delimiter at the end of the file, so we enqueue the byte range.
229
+ this.#indices.enqueue([possibleDelimiterIndex + this.#needle.length, this.#controller.bytesWritten]);
230
+ }
231
+ else {
232
+ this.#log("Inserted byte range at the last byte", [lastByteIndex, this.#controller.bytesWritten]);
233
+ // The file didn't end with a delimiter, so we just enqueue the last byte range.
234
+ this.#indices.enqueue([lastByteIndex + this.#needle.length, this.#controller.bytesWritten]);
235
+ }
236
+ }
237
+ else {
238
+ this.#log(`Weird situation. We're at the end of the file, but the last byte range ${lastByteIndex} is greater than the buffer length ${this.#controller.bytesWritten}.`);
239
+ }
240
+ }
241
+ else if (this.#yieldCount === 0) {
242
+ // We didn't find any delimiters in the file, so we just enqueue the whole buffer.
243
+ this.#indices.enqueue([0, this.#controller.bytesWritten]);
244
+ }
245
+ this.#done = true;
246
+ return;
247
+ }
248
+ // We're effectively done with that window of the buffer.
249
+ // So we can compress it to save memory.
250
+ const nextBufferStart = this.#lastByteRangeSeen ? this.#lastByteRangeSeen[1] + this.#needle.length : 0;
251
+ this.#log("Compressing buffer", { nextBufferStart });
252
+ this.#controller.compress(nextBufferStart);
253
+ while (this.#readPosition < this.#totalByteSize && this.#indices.byteLength < this.#highWaterMark) {
254
+ await this.#read();
255
+ this.#search();
256
+ }
257
+ }
258
+ async #finalize() {
259
+ if (this.#debug) {
260
+ /**
261
+ * The total number of bytes we expect to be omitted from the buffer. This is derived from the
262
+ * number of of yields and the length of the delimiter.
263
+ */
264
+ const expectedYieldedDelimitedBytes = (this.#yieldCount - 1) * this.#needle.length;
265
+ const omittedBytes = this.#yieldByteEstimate - (this.#yieldedByteLength + expectedYieldedDelimitedBytes);
266
+ this.#log({
267
+ totalByteSize: this.#totalByteSize,
268
+ readPosition: this.#readPosition,
269
+ yieldByteEstimate: this.#yieldByteEstimate,
270
+ yieldedByteLength: this.#yieldedByteLength,
271
+ yieldCount: this.#yieldCount,
272
+ expectedYieldedDelimitedBytes,
273
+ omittedBytes,
274
+ });
275
+ }
276
+ if (this.#autoClose) {
277
+ await this.#file[Symbol.asyncDispose]?.();
278
+ }
279
+ return {
280
+ done: true,
281
+ value: undefined,
282
+ };
283
+ }
284
+ //#endregion
285
+ //#region Iterator Methods
286
+ async next() {
287
+ if (this.#done || this.#yieldCount >= this.#yieldStopCount)
288
+ return this.#finalize();
289
+ if (this.#indices.size === 0) {
290
+ await this.#fill();
291
+ }
292
+ const currentByteRange = this.#indices.dequeue();
293
+ this.#lastByteRangeSeen = currentByteRange;
294
+ const [start, end] = currentByteRange;
295
+ const slice = this.#controller.subarray(start, end);
296
+ if (slice.length === 0 && this.#skipEmpty) {
297
+ return this.next();
298
+ }
299
+ this.#yieldCount++;
300
+ if (this.#yieldCount <= this.#yieldDropCount) {
301
+ return this.next();
302
+ }
303
+ this.#yieldedByteLength += end - start;
304
+ return {
305
+ value: slice,
306
+ done: false,
307
+ };
308
+ }
309
+ /**
310
+ * Collect all the byte ranges from the file.
311
+ *
312
+ * **This method will read the entire file into memory.**
313
+ */
314
+ toArray() {
315
+ return Array.fromAsync(this);
316
+ }
317
+ /**
318
+ * Collect all the byte ranges from the file as a string.
319
+ *
320
+ * **This method will read the entire file into memory.**
321
+ */
322
+ toDecodedArray(decoder = new TextDecoder()) {
323
+ return Array.fromAsync(this, (bytes) => decoder.decode(bytes));
324
+ }
325
+ [Symbol.asyncIterator]() {
326
+ return this;
327
+ }
328
+ return() {
329
+ return this.#finalize();
330
+ }
331
+ }
332
+ //# sourceMappingURL=AsyncSpliterator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AsyncSpliterator.js","sourceRoot":"","sources":["../../lib/AsyncSpliterator.ts"],"names":[],"mappings":"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"}