@yume-chan/stream-extra 0.0.17 → 0.0.19
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/CHANGELOG.json +33 -9
- package/CHANGELOG.md +15 -2
- package/LICENSE +1 -1
- package/README.md +35 -3
- package/esm/buffered-transform.d.ts +11 -10
- package/esm/buffered-transform.d.ts.map +1 -1
- package/esm/buffered-transform.js +55 -49
- package/esm/buffered-transform.js.map +1 -1
- package/esm/buffered.d.ts +29 -27
- package/esm/buffered.d.ts.map +1 -1
- package/esm/buffered.js +128 -130
- package/esm/buffered.js.map +1 -1
- package/esm/chunk.d.ts +7 -4
- package/esm/chunk.d.ts.map +1 -1
- package/esm/chunk.js +48 -7
- package/esm/chunk.js.map +1 -1
- package/esm/consumable.d.ts +53 -0
- package/esm/consumable.d.ts.map +1 -0
- package/esm/consumable.js +178 -0
- package/esm/consumable.js.map +1 -0
- package/esm/decode-utf8.d.ts +4 -4
- package/esm/decode-utf8.d.ts.map +1 -1
- package/esm/decode-utf8.js +11 -11
- package/esm/decode-utf8.js.map +1 -1
- package/esm/distribution.d.ts +24 -0
- package/esm/distribution.d.ts.map +1 -0
- package/esm/distribution.js +99 -0
- package/esm/distribution.js.map +1 -0
- package/esm/duplex.d.ts +48 -47
- package/esm/duplex.d.ts.map +1 -1
- package/esm/duplex.js +90 -88
- package/esm/duplex.js.map +1 -1
- package/esm/gather-string.d.ts +6 -6
- package/esm/gather-string.d.ts.map +1 -1
- package/esm/gather-string.js +15 -13
- package/esm/gather-string.js.map +1 -1
- package/esm/index.d.ts +16 -15
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +16 -15
- package/esm/index.js.map +1 -1
- package/esm/inspect.d.ts +4 -4
- package/esm/inspect.js +11 -11
- package/esm/pipe-from.d.ts +12 -12
- package/esm/pipe-from.d.ts.map +1 -1
- package/esm/pipe-from.js +23 -26
- package/esm/pipe-from.js.map +1 -1
- package/esm/push-readable.d.ts +19 -11
- package/esm/push-readable.d.ts.map +1 -1
- package/esm/push-readable.js +61 -46
- package/esm/push-readable.js.map +1 -1
- package/esm/split-string.d.ts +4 -4
- package/esm/split-string.d.ts.map +1 -1
- package/esm/split-string.js +24 -24
- package/esm/split-string.js.map +1 -1
- package/esm/stream.d.ts +25 -17
- package/esm/stream.d.ts.map +1 -1
- package/esm/stream.js +26 -3
- package/esm/stream.js.map +1 -1
- package/esm/struct-deserialize.d.ts +6 -6
- package/esm/struct-deserialize.d.ts.map +1 -1
- package/esm/struct-deserialize.js +8 -8
- package/esm/struct-deserialize.js.map +1 -1
- package/esm/struct-serialize.d.ts +5 -5
- package/esm/struct-serialize.d.ts.map +1 -1
- package/esm/struct-serialize.js +10 -10
- package/esm/struct-serialize.js.map +1 -1
- package/esm/trace.d.ts +16 -0
- package/esm/trace.d.ts.map +1 -0
- package/esm/trace.js +131 -0
- package/esm/trace.js.map +1 -0
- package/esm/wrap-readable.d.ts +21 -20
- package/esm/wrap-readable.d.ts.map +1 -1
- package/esm/wrap-readable.js +56 -56
- package/esm/wrap-readable.js.map +1 -1
- package/esm/wrap-writable.d.ts +14 -12
- package/esm/wrap-writable.d.ts.map +1 -1
- package/esm/wrap-writable.js +62 -52
- package/esm/wrap-writable.js.map +1 -1
- package/package.json +13 -9
- package/src/buffered-transform.ts +32 -17
- package/src/buffered.ts +14 -15
- package/src/consumable.ts +281 -0
- package/src/decode-utf8.ts +3 -2
- package/src/distribution.ts +113 -0
- package/src/duplex.ts +27 -10
- package/src/gather-string.ts +5 -3
- package/src/index.ts +16 -15
- package/src/inspect.ts +1 -1
- package/src/pipe-from.ts +11 -10
- package/src/push-readable.ts +77 -46
- package/src/split-string.ts +5 -2
- package/src/stream.ts +48 -6
- package/src/struct-deserialize.ts +6 -4
- package/src/struct-serialize.ts +4 -2
- package/src/wrap-readable.ts +30 -12
- package/src/wrap-writable.ts +34 -11
- package/tsconfig.build.json +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/esm/native.d.ts +0 -240
- package/esm/native.d.ts.map +0 -1
- package/esm/native.js +0 -60
- package/esm/native.js.map +0 -1
- package/src/chunk.ts +0 -15
- package/src/native.ts +0 -362
package/esm/wrap-writable.js
CHANGED
|
@@ -1,53 +1,63 @@
|
|
|
1
|
-
import { WritableStream } from "./stream.js";
|
|
2
|
-
async function getWrappedWritableStream(wrapper) {
|
|
3
|
-
if (
|
|
4
|
-
return await wrapper.start();
|
|
5
|
-
}
|
|
6
|
-
else if (typeof wrapper ===
|
|
7
|
-
return await wrapper();
|
|
8
|
-
}
|
|
9
|
-
else {
|
|
10
|
-
// Can't use `wrapper instanceof WritableStream`
|
|
11
|
-
// Because we want to be compatible with any WritableStream-like objects
|
|
12
|
-
return wrapper;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
export class WrapWritableStream extends WritableStream {
|
|
16
|
-
writable;
|
|
17
|
-
writer;
|
|
18
|
-
constructor(wrapper) {
|
|
19
|
-
super({
|
|
20
|
-
start: async () => {
|
|
21
|
-
// `start` is invoked before `ReadableStream`'s constructor finish,
|
|
22
|
-
// so using `this` synchronously causes
|
|
23
|
-
// "Must call super constructor in derived class before accessing 'this' or returning from derived constructor".
|
|
24
|
-
// Queue a microtask to avoid this.
|
|
25
|
-
await Promise.resolve();
|
|
26
|
-
this.writable = await getWrappedWritableStream(wrapper);
|
|
27
|
-
this.writer = this.writable.getWriter();
|
|
28
|
-
},
|
|
29
|
-
write: async (chunk) => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
1
|
+
import { WritableStream } from "./stream.js";
|
|
2
|
+
async function getWrappedWritableStream(wrapper) {
|
|
3
|
+
if ("start" in wrapper) {
|
|
4
|
+
return await wrapper.start();
|
|
5
|
+
}
|
|
6
|
+
else if (typeof wrapper === "function") {
|
|
7
|
+
return await wrapper();
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
// Can't use `wrapper instanceof WritableStream`
|
|
11
|
+
// Because we want to be compatible with any WritableStream-like objects
|
|
12
|
+
return wrapper;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export class WrapWritableStream extends WritableStream {
|
|
16
|
+
writable;
|
|
17
|
+
writer;
|
|
18
|
+
constructor(wrapper) {
|
|
19
|
+
super({
|
|
20
|
+
start: async () => {
|
|
21
|
+
// `start` is invoked before `ReadableStream`'s constructor finish,
|
|
22
|
+
// so using `this` synchronously causes
|
|
23
|
+
// "Must call super constructor in derived class before accessing 'this' or returning from derived constructor".
|
|
24
|
+
// Queue a microtask to avoid this.
|
|
25
|
+
await Promise.resolve();
|
|
26
|
+
this.writable = await getWrappedWritableStream(wrapper);
|
|
27
|
+
this.writer = this.writable.getWriter();
|
|
28
|
+
},
|
|
29
|
+
write: async (chunk) => {
|
|
30
|
+
await this.writer.write(chunk);
|
|
31
|
+
},
|
|
32
|
+
abort: async (reason) => {
|
|
33
|
+
await this.writer.abort(reason);
|
|
34
|
+
if ("close" in wrapper) {
|
|
35
|
+
await wrapper.close?.();
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
close: async () => {
|
|
39
|
+
// Close the inner stream first.
|
|
40
|
+
// Usually the inner stream is a logical sub-stream over the outer stream,
|
|
41
|
+
// closing the outer stream first will make the inner stream incapable of
|
|
42
|
+
// sending data in its `close` handler.
|
|
43
|
+
await this.writer.close();
|
|
44
|
+
if ("close" in wrapper) {
|
|
45
|
+
await wrapper.close?.();
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
bePipedThroughFrom(transformer) {
|
|
51
|
+
let promise;
|
|
52
|
+
return new WrapWritableStream({
|
|
53
|
+
start: () => {
|
|
54
|
+
promise = transformer.readable.pipeTo(this);
|
|
55
|
+
return transformer.writable;
|
|
56
|
+
},
|
|
57
|
+
async close() {
|
|
58
|
+
await promise;
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
53
63
|
//# sourceMappingURL=wrap-writable.js.map
|
package/esm/wrap-writable.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrap-writable.js","sourceRoot":"","sources":["../src/wrap-writable.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"wrap-writable.js","sourceRoot":"","sources":["../src/wrap-writable.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAW7C,KAAK,UAAU,wBAAwB,CACnC,OAG8B;IAE9B,IAAI,OAAO,IAAI,OAAO,EAAE;QACpB,OAAO,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;KAChC;SAAM,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE;QACtC,OAAO,MAAM,OAAO,EAAE,CAAC;KAC1B;SAAM;QACH,gDAAgD;QAChD,wEAAwE;QACxE,OAAO,OAAO,CAAC;KAClB;AACL,CAAC;AAED,MAAM,OAAO,kBAAsB,SAAQ,cAAiB;IACjD,QAAQ,CAAqB;IAE5B,MAAM,CAAkC;IAEhD,YACI,OAG8B;QAE9B,KAAK,CAAC;YACF,KAAK,EAAE,KAAK,IAAI,EAAE;gBACd,mEAAmE;gBACnE,uCAAuC;gBACvC,gHAAgH;gBAChH,mCAAmC;gBACnC,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;gBAExB,IAAI,CAAC,QAAQ,GAAG,MAAM,wBAAwB,CAAC,OAAO,CAAC,CAAC;gBACxD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;YAC5C,CAAC;YACD,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;gBACnB,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACnC,CAAC;YACD,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;gBACpB,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAChC,IAAI,OAAO,IAAI,OAAO,EAAE;oBACpB,MAAM,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;iBAC3B;YACL,CAAC;YACD,KAAK,EAAE,KAAK,IAAI,EAAE;gBACd,gCAAgC;gBAChC,0EAA0E;gBAC1E,yEAAyE;gBACzE,uCAAuC;gBACvC,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;gBAC1B,IAAI,OAAO,IAAI,OAAO,EAAE;oBACpB,MAAM,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;iBAC3B;YACL,CAAC;SACJ,CAAC,CAAC;IACP,CAAC;IAEM,kBAAkB,CAAI,WAAkC;QAC3D,IAAI,OAAsB,CAAC;QAC3B,OAAO,IAAI,kBAAkB,CAAI;YAC7B,KAAK,EAAE,GAAG,EAAE;gBACR,OAAO,GAAG,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC5C,OAAO,WAAW,CAAC,QAAQ,CAAC;YAChC,CAAC;YACD,KAAK,CAAC,KAAK;gBACP,MAAM,OAAO,CAAC;YAClB,CAAC;SACJ,CAAC,CAAC;IACP,CAAC;CACJ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yume-chan/stream-extra",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.19",
|
|
4
4
|
"description": "Extensions to Web Streams API",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"stream",
|
|
@@ -26,21 +26,25 @@
|
|
|
26
26
|
"types": "esm/index.d.ts",
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@yume-chan/async": "^2.2.0",
|
|
29
|
-
"@yume-chan/struct": "^0.0.
|
|
30
|
-
"tslib": "^2.4.
|
|
29
|
+
"@yume-chan/struct": "^0.0.19",
|
|
30
|
+
"tslib": "^2.4.1",
|
|
31
31
|
"web-streams-polyfill": "^4.0.0-beta.3"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@jest/globals": "^
|
|
35
|
-
"@yume-chan/
|
|
34
|
+
"@jest/globals": "^29.5.0",
|
|
35
|
+
"@yume-chan/eslint-config": "^1.0.0",
|
|
36
|
+
"@yume-chan/tsconfig": "^1.0.0",
|
|
36
37
|
"cross-env": "^7.0.3",
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
38
|
+
"eslint": "^8.36.0",
|
|
39
|
+
"jest": "^29.5.0",
|
|
40
|
+
"prettier": "^2.8.4",
|
|
41
|
+
"ts-jest": "^29.0.4",
|
|
42
|
+
"typescript": "^4.9.4"
|
|
40
43
|
},
|
|
41
44
|
"scripts": {
|
|
42
45
|
"build": "tsc -b tsconfig.build.json",
|
|
43
46
|
"build:watch": "tsc -b tsconfig.build.json",
|
|
44
|
-
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --coverage"
|
|
47
|
+
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --coverage",
|
|
48
|
+
"lint": "eslint src/**/*.ts --fix && prettier src/**/*.ts --write --tab-width 4"
|
|
45
49
|
}
|
|
46
50
|
}
|
|
@@ -1,24 +1,39 @@
|
|
|
1
|
-
import type { ValueOrPromise } from
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
1
|
+
import type { ValueOrPromise } from "@yume-chan/struct";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
BufferedReadableStream,
|
|
5
|
+
BufferedReadableStreamEndedError,
|
|
6
|
+
} from "./buffered.js";
|
|
7
|
+
import type { PushReadableStreamController } from "./push-readable.js";
|
|
8
|
+
import { PushReadableStream } from "./push-readable.js";
|
|
9
|
+
import type { ReadableWritablePair } from "./stream.js";
|
|
10
|
+
import { ReadableStream, WritableStream } from "./stream.js";
|
|
5
11
|
|
|
6
12
|
// TODO: BufferedTransformStream: find better implementation
|
|
7
|
-
export class BufferedTransformStream<T>
|
|
13
|
+
export class BufferedTransformStream<T>
|
|
14
|
+
implements ReadableWritablePair<T, Uint8Array>
|
|
15
|
+
{
|
|
8
16
|
private _readable: ReadableStream<T>;
|
|
9
|
-
public get readable() {
|
|
17
|
+
public get readable() {
|
|
18
|
+
return this._readable;
|
|
19
|
+
}
|
|
10
20
|
|
|
11
21
|
private _writable: WritableStream<Uint8Array>;
|
|
12
|
-
public get writable() {
|
|
22
|
+
public get writable() {
|
|
23
|
+
return this._writable;
|
|
24
|
+
}
|
|
13
25
|
|
|
14
|
-
constructor(
|
|
26
|
+
constructor(
|
|
27
|
+
transform: (stream: BufferedReadableStream) => ValueOrPromise<T>
|
|
28
|
+
) {
|
|
15
29
|
// Convert incoming chunks to a `BufferedReadableStream`
|
|
16
30
|
let sourceStreamController!: PushReadableStreamController<Uint8Array>;
|
|
17
31
|
|
|
18
|
-
const buffered = new BufferedReadableStream(
|
|
19
|
-
controller =>
|
|
20
|
-
sourceStreamController = controller
|
|
21
|
-
|
|
32
|
+
const buffered = new BufferedReadableStream(
|
|
33
|
+
new PushReadableStream<Uint8Array>((controller) => {
|
|
34
|
+
sourceStreamController = controller;
|
|
35
|
+
})
|
|
36
|
+
);
|
|
22
37
|
|
|
23
38
|
this._readable = new ReadableStream<T>({
|
|
24
39
|
async pull(controller) {
|
|
@@ -26,9 +41,9 @@ export class BufferedTransformStream<T> implements ReadableWritablePair<T, Uint8
|
|
|
26
41
|
const value = await transform(buffered);
|
|
27
42
|
controller.enqueue(value);
|
|
28
43
|
} catch (e) {
|
|
29
|
-
//
|
|
30
|
-
// If the `transform`
|
|
31
|
-
//
|
|
44
|
+
// Treat `BufferedReadableStreamEndedError` as a normal end.
|
|
45
|
+
// If the `transform` method doesn't have enough data to return a value,
|
|
46
|
+
// it should throw another error to indicate that.
|
|
32
47
|
if (e instanceof BufferedReadableStreamEndedError) {
|
|
33
48
|
controller.close();
|
|
34
49
|
return;
|
|
@@ -39,8 +54,8 @@ export class BufferedTransformStream<T> implements ReadableWritablePair<T, Uint8
|
|
|
39
54
|
cancel: (reason) => {
|
|
40
55
|
// Propagate cancel to the source stream
|
|
41
56
|
// So future writes will be rejected
|
|
42
|
-
buffered.cancel(reason);
|
|
43
|
-
}
|
|
57
|
+
return buffered.cancel(reason);
|
|
58
|
+
},
|
|
44
59
|
});
|
|
45
60
|
|
|
46
61
|
this._writable = new WritableStream({
|
package/src/buffered.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { ReadableStream, ReadableStreamDefaultReader } from "./stream.js";
|
|
|
3
3
|
|
|
4
4
|
export class BufferedReadableStreamEndedError extends Error {
|
|
5
5
|
public constructor() {
|
|
6
|
-
super(
|
|
6
|
+
super("Stream ended");
|
|
7
7
|
|
|
8
8
|
// Fix Error's prototype chain when compiling to ES5
|
|
9
9
|
Object.setPrototypeOf(this, new.target.prototype);
|
|
@@ -15,8 +15,12 @@ export class BufferedReadableStream {
|
|
|
15
15
|
private bufferedOffset = 0;
|
|
16
16
|
private bufferedLength = 0;
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
private _position = 0;
|
|
19
|
+
public get position() {
|
|
20
|
+
return this._position;
|
|
21
|
+
}
|
|
19
22
|
|
|
23
|
+
protected readonly stream: ReadableStream<Uint8Array>;
|
|
20
24
|
protected readonly reader: ReadableStreamDefaultReader<Uint8Array>;
|
|
21
25
|
|
|
22
26
|
public constructor(stream: ReadableStream<Uint8Array>) {
|
|
@@ -29,6 +33,7 @@ export class BufferedReadableStream {
|
|
|
29
33
|
if (done) {
|
|
30
34
|
throw new BufferedReadableStreamEndedError();
|
|
31
35
|
}
|
|
36
|
+
this._position += value.byteLength;
|
|
32
37
|
return value;
|
|
33
38
|
}
|
|
34
39
|
|
|
@@ -115,23 +120,17 @@ export class BufferedReadableStream {
|
|
|
115
120
|
*/
|
|
116
121
|
public release(): ReadableStream<Uint8Array> {
|
|
117
122
|
if (this.buffered) {
|
|
118
|
-
return new PushReadableStream<Uint8Array>(async controller => {
|
|
123
|
+
return new PushReadableStream<Uint8Array>(async (controller) => {
|
|
119
124
|
// Put the remaining data back to the stream
|
|
120
125
|
await controller.enqueue(this.buffered!);
|
|
121
126
|
|
|
122
127
|
// Manually pipe the stream
|
|
123
128
|
while (true) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
} else {
|
|
130
|
-
await controller.enqueue(value);
|
|
131
|
-
}
|
|
132
|
-
} catch (e) {
|
|
133
|
-
controller.error(e);
|
|
134
|
-
break;
|
|
129
|
+
const { done, value } = await this.reader.read();
|
|
130
|
+
if (done) {
|
|
131
|
+
return;
|
|
132
|
+
} else {
|
|
133
|
+
await controller.enqueue(value);
|
|
135
134
|
}
|
|
136
135
|
}
|
|
137
136
|
});
|
|
@@ -142,7 +141,7 @@ export class BufferedReadableStream {
|
|
|
142
141
|
}
|
|
143
142
|
}
|
|
144
143
|
|
|
145
|
-
public cancel(reason?:
|
|
144
|
+
public cancel(reason?: unknown) {
|
|
146
145
|
return this.reader.cancel(reason);
|
|
147
146
|
}
|
|
148
147
|
}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { PromiseResolver } from "@yume-chan/async";
|
|
2
|
+
|
|
3
|
+
import type { QueuingStrategy, WritableStreamDefaultWriter } from "./stream.js";
|
|
4
|
+
import { ReadableStream, TransformStream, WritableStream } from "./stream.js";
|
|
5
|
+
|
|
6
|
+
interface Task {
|
|
7
|
+
run<T>(callback: () => T): T;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface Console {
|
|
11
|
+
createTask(name: string): Task;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface GlobalEx {
|
|
15
|
+
console: Console;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// `createTask` allows browser DevTools to track the call stack across async boundaries.
|
|
19
|
+
const { console } = globalThis as unknown as GlobalEx;
|
|
20
|
+
const createTask: Console["createTask"] =
|
|
21
|
+
console.createTask?.bind(console) ??
|
|
22
|
+
(() => ({
|
|
23
|
+
run(callback) {
|
|
24
|
+
return callback();
|
|
25
|
+
},
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
export class Consumable<T> {
|
|
29
|
+
private readonly task: Task;
|
|
30
|
+
private readonly resolver: PromiseResolver<void>;
|
|
31
|
+
|
|
32
|
+
public readonly value: T;
|
|
33
|
+
public readonly consumed: Promise<void>;
|
|
34
|
+
|
|
35
|
+
public constructor(value: T) {
|
|
36
|
+
this.task = createTask("Consumable");
|
|
37
|
+
this.value = value;
|
|
38
|
+
this.resolver = new PromiseResolver<void>();
|
|
39
|
+
this.consumed = this.resolver.promise;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public consume() {
|
|
43
|
+
this.resolver.resolve();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public error(error: any) {
|
|
47
|
+
this.resolver.reject(error);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public async tryConsume<U>(callback: (value: T) => U) {
|
|
51
|
+
try {
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/await-thenable
|
|
53
|
+
const result = await this.task.run(() => callback(this.value));
|
|
54
|
+
this.consume();
|
|
55
|
+
return result;
|
|
56
|
+
} catch (e) {
|
|
57
|
+
this.resolver.reject(e);
|
|
58
|
+
throw e;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function enqueue<T>(
|
|
64
|
+
controller: { enqueue: (chunk: Consumable<T>) => void },
|
|
65
|
+
chunk: T
|
|
66
|
+
) {
|
|
67
|
+
const output = new Consumable(chunk);
|
|
68
|
+
controller.enqueue(output);
|
|
69
|
+
await output.consumed;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export class WrapConsumableStream<T> extends TransformStream<T, Consumable<T>> {
|
|
73
|
+
public constructor() {
|
|
74
|
+
super({
|
|
75
|
+
async transform(chunk, controller) {
|
|
76
|
+
await enqueue(controller, chunk);
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export class UnwrapConsumableStream<T> extends TransformStream<
|
|
83
|
+
Consumable<T>,
|
|
84
|
+
T
|
|
85
|
+
> {
|
|
86
|
+
public constructor() {
|
|
87
|
+
super({
|
|
88
|
+
transform(chunk, controller) {
|
|
89
|
+
controller.enqueue(chunk.value);
|
|
90
|
+
chunk.consume();
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface ConsumableReadableStreamController<T> {
|
|
97
|
+
enqueue(chunk: T): Promise<void>;
|
|
98
|
+
close(): void;
|
|
99
|
+
error(reason: any): void;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface ConsumableReadableStreamSource<T> {
|
|
103
|
+
start?(
|
|
104
|
+
controller: ConsumableReadableStreamController<T>
|
|
105
|
+
): void | PromiseLike<void>;
|
|
106
|
+
pull?(
|
|
107
|
+
controller: ConsumableReadableStreamController<T>
|
|
108
|
+
): void | PromiseLike<void>;
|
|
109
|
+
cancel?(reason: any): void | PromiseLike<void>;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export class ConsumableReadableStream<T> extends ReadableStream<Consumable<T>> {
|
|
113
|
+
public constructor(
|
|
114
|
+
source: ConsumableReadableStreamSource<T>,
|
|
115
|
+
strategy?: QueuingStrategy<T>
|
|
116
|
+
) {
|
|
117
|
+
let wrappedController:
|
|
118
|
+
| ConsumableReadableStreamController<T>
|
|
119
|
+
| undefined;
|
|
120
|
+
|
|
121
|
+
let wrappedStrategy: QueuingStrategy<Consumable<T>> | undefined;
|
|
122
|
+
if (strategy) {
|
|
123
|
+
wrappedStrategy = {};
|
|
124
|
+
if ("highWaterMark" in strategy) {
|
|
125
|
+
wrappedStrategy.highWaterMark = strategy.highWaterMark;
|
|
126
|
+
}
|
|
127
|
+
if ("size" in strategy) {
|
|
128
|
+
wrappedStrategy.size = (chunk) => {
|
|
129
|
+
return strategy.size!(chunk.value);
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
super(
|
|
135
|
+
{
|
|
136
|
+
async start(controller) {
|
|
137
|
+
wrappedController = {
|
|
138
|
+
async enqueue(chunk) {
|
|
139
|
+
await enqueue(controller, chunk);
|
|
140
|
+
},
|
|
141
|
+
close() {
|
|
142
|
+
controller.close();
|
|
143
|
+
},
|
|
144
|
+
error(reason) {
|
|
145
|
+
controller.error(reason);
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
await source.start?.(wrappedController);
|
|
150
|
+
},
|
|
151
|
+
async pull() {
|
|
152
|
+
await source.pull?.(wrappedController!);
|
|
153
|
+
},
|
|
154
|
+
async cancel(reason) {
|
|
155
|
+
await source.cancel?.(reason);
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
wrappedStrategy
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface ConsumableWritableStreamSink<T> {
|
|
164
|
+
start?(): void | PromiseLike<void>;
|
|
165
|
+
write?(chunk: T): void | PromiseLike<void>;
|
|
166
|
+
abort?(reason: any): void | PromiseLike<void>;
|
|
167
|
+
close?(): void | PromiseLike<void>;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export class ConsumableWritableStream<T> extends WritableStream<Consumable<T>> {
|
|
171
|
+
public static async write<T>(
|
|
172
|
+
writer: WritableStreamDefaultWriter<Consumable<T>>,
|
|
173
|
+
value: T
|
|
174
|
+
) {
|
|
175
|
+
const consumable = new Consumable(value);
|
|
176
|
+
await writer.write(consumable);
|
|
177
|
+
await consumable.consumed;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
public constructor(
|
|
181
|
+
sink: ConsumableWritableStreamSink<T>,
|
|
182
|
+
strategy?: QueuingStrategy<T>
|
|
183
|
+
) {
|
|
184
|
+
let wrappedStrategy: QueuingStrategy<Consumable<T>> | undefined;
|
|
185
|
+
if (strategy) {
|
|
186
|
+
wrappedStrategy = {};
|
|
187
|
+
if ("highWaterMark" in strategy) {
|
|
188
|
+
wrappedStrategy.highWaterMark = strategy.highWaterMark;
|
|
189
|
+
}
|
|
190
|
+
if ("size" in strategy) {
|
|
191
|
+
wrappedStrategy.size = (chunk) => {
|
|
192
|
+
return strategy.size!(chunk.value);
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
super(
|
|
198
|
+
{
|
|
199
|
+
start() {
|
|
200
|
+
return sink.start?.();
|
|
201
|
+
},
|
|
202
|
+
async write(chunk) {
|
|
203
|
+
await chunk.tryConsume((value) => sink.write?.(value));
|
|
204
|
+
chunk.consume();
|
|
205
|
+
},
|
|
206
|
+
abort(reason) {
|
|
207
|
+
return sink.abort?.(reason);
|
|
208
|
+
},
|
|
209
|
+
close() {
|
|
210
|
+
return sink.close?.();
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
wrappedStrategy
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export interface ConsumableTransformer<I, O> {
|
|
219
|
+
start?(
|
|
220
|
+
controller: ConsumableReadableStreamController<O>
|
|
221
|
+
): void | PromiseLike<void>;
|
|
222
|
+
transform?(
|
|
223
|
+
chunk: I,
|
|
224
|
+
controller: ConsumableReadableStreamController<O>
|
|
225
|
+
): void | PromiseLike<void>;
|
|
226
|
+
flush?(
|
|
227
|
+
controller: ConsumableReadableStreamController<O>
|
|
228
|
+
): void | PromiseLike<void>;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export class ConsumableTransformStream<I, O> extends TransformStream<
|
|
232
|
+
Consumable<I>,
|
|
233
|
+
Consumable<O>
|
|
234
|
+
> {
|
|
235
|
+
public constructor(transformer: ConsumableTransformer<I, O>) {
|
|
236
|
+
let wrappedController:
|
|
237
|
+
| ConsumableReadableStreamController<O>
|
|
238
|
+
| undefined;
|
|
239
|
+
|
|
240
|
+
super({
|
|
241
|
+
async start(controller) {
|
|
242
|
+
wrappedController = {
|
|
243
|
+
async enqueue(chunk) {
|
|
244
|
+
await enqueue(controller, chunk);
|
|
245
|
+
},
|
|
246
|
+
close() {
|
|
247
|
+
controller.terminate();
|
|
248
|
+
},
|
|
249
|
+
error(reason) {
|
|
250
|
+
controller.error(reason);
|
|
251
|
+
},
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
await transformer.start?.(wrappedController);
|
|
255
|
+
},
|
|
256
|
+
async transform(chunk) {
|
|
257
|
+
await chunk.tryConsume((value) =>
|
|
258
|
+
transformer.transform?.(value, wrappedController!)
|
|
259
|
+
);
|
|
260
|
+
chunk.consume();
|
|
261
|
+
},
|
|
262
|
+
async flush() {
|
|
263
|
+
await transformer.flush?.(wrappedController!);
|
|
264
|
+
},
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export class ConsumableInspectStream<T> extends TransformStream<
|
|
270
|
+
Consumable<T>,
|
|
271
|
+
Consumable<T>
|
|
272
|
+
> {
|
|
273
|
+
public constructor(callback: (value: T) => void) {
|
|
274
|
+
super({
|
|
275
|
+
transform(chunk, controller) {
|
|
276
|
+
callback(chunk.value);
|
|
277
|
+
controller.enqueue(chunk);
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
}
|
package/src/decode-utf8.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { decodeUtf8 } from
|
|
1
|
+
import { decodeUtf8 } from "@yume-chan/struct";
|
|
2
|
+
|
|
2
3
|
import { TransformStream } from "./stream.js";
|
|
3
4
|
|
|
4
|
-
export class DecodeUtf8Stream extends TransformStream<Uint8Array, string>{
|
|
5
|
+
export class DecodeUtf8Stream extends TransformStream<Uint8Array, string> {
|
|
5
6
|
public constructor() {
|
|
6
7
|
super({
|
|
7
8
|
transform(chunk, controller) {
|