@effectionx/stream-helpers 0.7.1 → 0.7.2
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 +66 -0
- package/batch.test.ts +2 -2
- package/dist/drain.d.ts +24 -0
- package/dist/drain.d.ts.map +1 -0
- package/dist/drain.js +33 -0
- package/dist/first.d.ts +28 -0
- package/dist/first.d.ts.map +1 -0
- package/dist/first.js +67 -0
- package/dist/for-each.d.ts.map +1 -1
- package/dist/for-each.js +12 -8
- package/dist/last.d.ts +29 -0
- package/dist/last.d.ts.map +1 -0
- package/dist/last.js +81 -0
- package/dist/mod.d.ts +3 -0
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +3 -0
- package/dist/test-helpers/faucet.d.ts.map +1 -1
- package/dist/test-helpers/faucet.js +28 -24
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/drain.test.ts +52 -0
- package/drain.ts +35 -0
- package/first.test.ts +53 -0
- package/first.ts +74 -0
- package/for-each.ts +12 -8
- package/last.test.ts +65 -0
- package/last.ts +96 -0
- package/mod.ts +3 -0
- package/package.json +5 -4
- package/test-helpers/faucet.test.ts +3 -3
- package/test-helpers/faucet.ts +28 -24
- package/tracker.test.ts +4 -4
- package/valve.test.ts +2 -2
package/last.test.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { describe, it } from "@effectionx/bdd";
|
|
2
|
+
import { expect } from "expect";
|
|
3
|
+
|
|
4
|
+
import { last } from "./last.ts";
|
|
5
|
+
import { streamOf } from "./stream-of.ts";
|
|
6
|
+
|
|
7
|
+
describe("last", () => {
|
|
8
|
+
it("should return the last value from the stream", function* () {
|
|
9
|
+
const stream = streamOf([1, 2, 3]);
|
|
10
|
+
const value = yield* last(stream);
|
|
11
|
+
expect(value).toBe(3);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should return the only value when stream has one item", function* () {
|
|
15
|
+
const stream = streamOf([42]);
|
|
16
|
+
const value = yield* last(stream);
|
|
17
|
+
expect(value).toBe(42);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("should return undefined if stream closes without yielding any values", function* () {
|
|
21
|
+
const stream = streamOf([]);
|
|
22
|
+
const value = yield* last(stream);
|
|
23
|
+
expect(value).toBe(undefined);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("should work with undefined as a valid value", function* () {
|
|
27
|
+
const stream = streamOf([1, 2, undefined]);
|
|
28
|
+
const value = yield* last(stream);
|
|
29
|
+
expect(value).toBe(undefined);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe("expect", () => {
|
|
33
|
+
it("should return the last value from the stream", function* () {
|
|
34
|
+
const stream = streamOf([1, 2, 3]);
|
|
35
|
+
const value = yield* last.expect(stream);
|
|
36
|
+
expect(value).toBe(3);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("should return the only value when stream has one item", function* () {
|
|
40
|
+
const stream = streamOf([42]);
|
|
41
|
+
const value = yield* last.expect(stream);
|
|
42
|
+
expect(value).toBe(42);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("should throw if stream closes without yielding any values", function* () {
|
|
46
|
+
const stream = streamOf([]);
|
|
47
|
+
|
|
48
|
+
let error: Error | undefined;
|
|
49
|
+
try {
|
|
50
|
+
yield* last.expect(stream);
|
|
51
|
+
} catch (e) {
|
|
52
|
+
error = e as Error;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
expect(error).toBeDefined();
|
|
56
|
+
expect(error?.message).toBe("Stream closed without yielding any values");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("should work with undefined as a valid value", function* () {
|
|
60
|
+
const stream = streamOf([1, 2, undefined]);
|
|
61
|
+
const value = yield* last.expect(stream);
|
|
62
|
+
expect(value).toBe(undefined);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
});
|
package/last.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { Operation, Stream } from "effection";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Returns the last value yielded by a stream, or `undefined` if the stream
|
|
5
|
+
* closes without yielding any values.
|
|
6
|
+
*
|
|
7
|
+
* Exhausts the entire stream to find the last value.
|
|
8
|
+
* Use `last.expect()` if you want to throw an error when the stream is empty.
|
|
9
|
+
*
|
|
10
|
+
* @template T - The type of items in the stream
|
|
11
|
+
* @template TClose - The type of the close value (unused)
|
|
12
|
+
* @param stream - The stream to get the last value from
|
|
13
|
+
* @returns The last value yielded by the stream, or `undefined` if empty
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* import { last } from "./last.ts";
|
|
18
|
+
*
|
|
19
|
+
* const stream = streamOf([1, 2, 3]);
|
|
20
|
+
* const value = yield* last(stream); // returns 3
|
|
21
|
+
*
|
|
22
|
+
* const empty = streamOf([]);
|
|
23
|
+
* const value = yield* last(empty); // returns undefined
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function last<T, TClose>(
|
|
27
|
+
stream: Stream<T, TClose>,
|
|
28
|
+
): Operation<T | undefined> {
|
|
29
|
+
return {
|
|
30
|
+
*[Symbol.iterator]() {
|
|
31
|
+
const subscription = yield* stream;
|
|
32
|
+
const first = yield* subscription.next();
|
|
33
|
+
|
|
34
|
+
if (first.done) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let lastValue: T = first.value;
|
|
39
|
+
let result = yield* subscription.next();
|
|
40
|
+
|
|
41
|
+
while (!result.done) {
|
|
42
|
+
lastValue = result.value;
|
|
43
|
+
result = yield* subscription.next();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return lastValue;
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Returns the last value yielded by a stream.
|
|
53
|
+
* Exhausts the entire stream to find the last value.
|
|
54
|
+
* Throws an error if the stream closes without yielding any values.
|
|
55
|
+
*
|
|
56
|
+
* @template T - The type of items in the stream
|
|
57
|
+
* @template TClose - The type of the close value (unused)
|
|
58
|
+
* @param stream - The stream to get the last value from
|
|
59
|
+
* @returns The last value yielded by the stream
|
|
60
|
+
* @throws Error if the stream closes without yielding any values
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* import { last } from "./last.ts";
|
|
65
|
+
*
|
|
66
|
+
* const stream = streamOf([1, 2, 3]);
|
|
67
|
+
* const value = yield* last.expect(stream); // returns 3
|
|
68
|
+
*
|
|
69
|
+
* const empty = streamOf([]);
|
|
70
|
+
* const value = yield* last.expect(empty); // throws Error
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
last.expect = function expectLast<T, TClose>(
|
|
74
|
+
stream: Stream<T, TClose>,
|
|
75
|
+
): Operation<T> {
|
|
76
|
+
return {
|
|
77
|
+
*[Symbol.iterator]() {
|
|
78
|
+
const subscription = yield* stream;
|
|
79
|
+
const first = yield* subscription.next();
|
|
80
|
+
|
|
81
|
+
if (first.done) {
|
|
82
|
+
throw new Error("Stream closed without yielding any values");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let lastValue: T = first.value;
|
|
86
|
+
let result = yield* subscription.next();
|
|
87
|
+
|
|
88
|
+
while (!result.done) {
|
|
89
|
+
lastValue = result.value;
|
|
90
|
+
result = yield* subscription.next();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return lastValue;
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
};
|
package/mod.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effectionx/stream-helpers",
|
|
3
|
-
"
|
|
3
|
+
"description": "Type-safe stream operators like filter, map, reduce, and forEach",
|
|
4
|
+
"version": "0.7.2",
|
|
4
5
|
"type": "module",
|
|
5
6
|
"main": "./dist/mod.js",
|
|
6
7
|
"types": "./dist/mod.d.ts",
|
|
@@ -20,8 +21,8 @@
|
|
|
20
21
|
"dependencies": {
|
|
21
22
|
"immutable": "^5",
|
|
22
23
|
"remeda": "^2",
|
|
23
|
-
"@effectionx/signals": "0.5.
|
|
24
|
-
"@effectionx/timebox": "0.4.
|
|
24
|
+
"@effectionx/signals": "0.5.1",
|
|
25
|
+
"@effectionx/timebox": "0.4.1"
|
|
25
26
|
},
|
|
26
27
|
"license": "MIT",
|
|
27
28
|
"author": "engineering@frontside.com",
|
|
@@ -37,6 +38,6 @@
|
|
|
37
38
|
},
|
|
38
39
|
"sideEffects": false,
|
|
39
40
|
"devDependencies": {
|
|
40
|
-
"@effectionx/bdd": "0.4.
|
|
41
|
+
"@effectionx/bdd": "0.4.2"
|
|
41
42
|
}
|
|
42
43
|
}
|
|
@@ -19,7 +19,7 @@ describe("useFaucet", () => {
|
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
yield* spawn(function* () {
|
|
22
|
-
yield* sleep(
|
|
22
|
+
yield* sleep(0);
|
|
23
23
|
// Pour an array of items
|
|
24
24
|
yield* faucet.pour([1, 2, 3]);
|
|
25
25
|
});
|
|
@@ -71,7 +71,7 @@ describe("useFaucet", () => {
|
|
|
71
71
|
|
|
72
72
|
// Pour using a generator function
|
|
73
73
|
yield* spawn(function* () {
|
|
74
|
-
yield* sleep(
|
|
74
|
+
yield* sleep(0);
|
|
75
75
|
yield* faucet.pour(function* (send) {
|
|
76
76
|
yield* send(1);
|
|
77
77
|
yield* sleep(10);
|
|
@@ -100,7 +100,7 @@ describe("useFaucet", () => {
|
|
|
100
100
|
|
|
101
101
|
// Start pouring with a generator
|
|
102
102
|
yield* spawn(function* () {
|
|
103
|
-
yield* sleep(
|
|
103
|
+
yield* sleep(0);
|
|
104
104
|
yield* faucet.pour(function* (send) {
|
|
105
105
|
yield* send(1);
|
|
106
106
|
yield* sleep(10);
|
package/test-helpers/faucet.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createChannel, type Operation, type Stream } from "effection";
|
|
2
1
|
import { createBooleanSignal, is } from "@effectionx/signals";
|
|
2
|
+
import { type Operation, type Stream, createChannel } from "effection";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Interface of the stream returned by `useFaucet`.
|
|
@@ -80,30 +80,34 @@ export interface FaucetOptions {
|
|
|
80
80
|
* @param options.open - Whether the faucet is open.
|
|
81
81
|
* @returns stream of items coming from the faucet
|
|
82
82
|
*/
|
|
83
|
-
export function
|
|
84
|
-
let signal = createChannel<T, never>();
|
|
85
|
-
let open = yield* createBooleanSignal(options.open);
|
|
86
|
-
|
|
83
|
+
export function useFaucet<T>(options: FaucetOptions): Operation<Faucet<T>> {
|
|
87
84
|
return {
|
|
88
|
-
[Symbol.iterator]
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
85
|
+
*[Symbol.iterator]() {
|
|
86
|
+
let signal = createChannel<T, never>();
|
|
87
|
+
let open = yield* createBooleanSignal(options.open);
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
[Symbol.iterator]: signal[Symbol.iterator],
|
|
91
|
+
*pour(items) {
|
|
92
|
+
if (Array.isArray(items)) {
|
|
93
|
+
for (let i of items) {
|
|
94
|
+
yield* is(open, (open) => open);
|
|
95
|
+
yield* signal.send(i);
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
yield* items(function* (item) {
|
|
99
|
+
yield* is(open, (open) => open);
|
|
100
|
+
yield* signal.send(item);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
close() {
|
|
105
|
+
open.set(false);
|
|
106
|
+
},
|
|
107
|
+
open() {
|
|
108
|
+
open.set(true);
|
|
109
|
+
},
|
|
110
|
+
};
|
|
107
111
|
},
|
|
108
112
|
};
|
|
109
113
|
}
|
package/tracker.test.ts
CHANGED
|
@@ -33,13 +33,13 @@ describe("tracker", () => {
|
|
|
33
33
|
}
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
yield* sleep(
|
|
36
|
+
yield* sleep(0);
|
|
37
37
|
|
|
38
38
|
yield* faucet.pour(function* (send) {
|
|
39
39
|
yield* send(1);
|
|
40
|
-
yield* sleep(
|
|
40
|
+
yield* sleep(0);
|
|
41
41
|
yield* send(2);
|
|
42
|
-
yield* sleep(
|
|
42
|
+
yield* sleep(0);
|
|
43
43
|
yield* send(3);
|
|
44
44
|
});
|
|
45
45
|
|
|
@@ -75,7 +75,7 @@ describe("tracker", () => {
|
|
|
75
75
|
}
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
-
yield* sleep(
|
|
78
|
+
yield* sleep(0);
|
|
79
79
|
|
|
80
80
|
yield* faucet.pour(function* (send) {
|
|
81
81
|
yield* send(1);
|
package/valve.test.ts
CHANGED
|
@@ -33,12 +33,12 @@ describe("valve", () => {
|
|
|
33
33
|
yield* spawn(function* () {
|
|
34
34
|
for (const value of yield* each(stream(faucet))) {
|
|
35
35
|
values.push(value);
|
|
36
|
-
yield* sleep(
|
|
36
|
+
yield* sleep(0);
|
|
37
37
|
yield* each.next();
|
|
38
38
|
}
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
yield* sleep(
|
|
41
|
+
yield* sleep(0);
|
|
42
42
|
|
|
43
43
|
yield* faucet.pour([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
|
|
44
44
|
|