Skip to content

Commit bbb9ced

Browse files
committed
API improvements
- Add 2-argument variant to pipe - Add stream.subject - Rename stream.stream to stream.generate - Rename signal.signal to signal.state (similar to TC39 signals)
1 parent 2845a0b commit bbb9ced

File tree

5 files changed

+34
-17
lines changed

5 files changed

+34
-17
lines changed

typescript/packages/common-frp/README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ Common functional reactive programming utilities.
1212
- [x] All graph dependencies held in array (in contrast to S.js style or Signals style where graph is defined via VM execution trace)
1313
- [x] Glitch free: updates happen during discrete moments using a transaction system
1414
- [x] Transformations should happen during same transaction
15-
- [ ] Transactions
16-
- [ ] (see experimental for WIP)
17-
- [ ] Cycles
18-
- [ ] TODO: switch from microtask-based topological sorting to transaction-based push-pull (see experimental for WIP)
15+
- [x] Transactions
16+
- [ ] Cycles supported for Signals
17+
- [ ] TODO need to improve [push-pull dirty marking logic](https://github.com/tc39/proposal-signals?tab=readme-ov-file#common-algorithms).
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { stream } from './stream.js'
1+
import { generate } from './stream.js'
22

33
export const events = (
44
element: HTMLElement,
55
name: string
6-
) => stream((send: (value: Event) => void) => {
6+
) => generate((send: (value: Event) => void) => {
77
element.addEventListener(name, send)
88
return () => element.removeEventListener(name, send)
99
})

typescript/packages/common-frp/src/operators.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ import {
1111
export type UnaryFn<A, B> = (a: A) => B
1212

1313
export type Pipe = {
14+
<A, B>(
15+
value: A,
16+
a2b: UnaryFn<A, B>
17+
): B
18+
1419
<A, B, C>(
1520
value: A,
1621
a2b: UnaryFn<A, B>,

typescript/packages/common-frp/src/signal.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export const effect = <T>(
9292
return signal[__updates__](() => withReads(job))
9393
}
9494

95-
export const signal = <T>(initial: T) => {
95+
export const state = <T>(initial: T) => {
9696
const updates = publisher<void>()
9797

9898
let state = initial

typescript/packages/common-frp/src/stream.ts

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { debug } from "./shared.js"
22
import { publisher, Send, Cancel, combineCancels } from "./publisher.js"
3-
import { signal as signal, Signal, __updates__ } from "./signal.js"
3+
import { state, Signal, __updates__ } from "./signal.js"
44

55
const __sink__ = Symbol('sink')
66

@@ -18,20 +18,33 @@ export const sink = <T>(
1818
subscriber: Send<T>
1919
) => upstream[__sink__](subscriber)
2020

21-
/** Create a new stream source */
22-
export const stream = <T>(
21+
/**
22+
* Create a stream subject - a source for a stream that has a send method
23+
* for publishing new items to stream.
24+
*/
25+
export const subject = <T>() => {
26+
const { pub, sub } = publisher<T>()
27+
return { [__sink__]: sub, send: pub }
28+
}
29+
30+
/**
31+
* Create a new stream source using a closure to publish new items to stream
32+
* Closure receives a single argument, a send function to publish new items,
33+
* and may return a cancel function to stop generation and clean up resources.
34+
*/
35+
export const generate = <T>(
2336
generate: (send: Send<T>) => Cancel | undefined
2437
): Stream<T> => {
25-
const { pub, sub } = publisher<T>()
26-
const cancel = generate(pub)
27-
return { [__sink__]: sub, cancel }
38+
const { [__sink__]: sink, send } = subject<T>()
39+
const cancel = generate(send)
40+
return { [__sink__]: sink, cancel }
2841
}
2942

3043
/** Map a stream of values */
3144
export const map = <T, U>(
3245
upstream: Stream<T>,
3346
transform: (value: T) => U
34-
) => stream<U>(send => {
47+
) => generate<U>(send => {
3548
return sink(upstream, value => send(transform(value)))
3649
})
3750

@@ -51,7 +64,7 @@ export const select = <T extends object, U extends keyof T & string>(
5164
export const filter = <T>(
5265
upstream: Stream<T>,
5366
predicate: (value: T) => boolean
54-
) => stream<T>(send => {
67+
) => generate<T>(send => {
5568
return sink(upstream, value => {
5669
if (predicate(value)) {
5770
send(value)
@@ -67,7 +80,7 @@ export const zip = <T, U, V>(
6780
left: Stream<T>,
6881
right: Stream<U>,
6982
combine: (left: T, right: U) => V
70-
) => stream<V>(send => {
83+
) => generate<V>(send => {
7184
const leftQueue: Array<T> = []
7285
const rightQueue: Array<U> = []
7386

@@ -100,7 +113,7 @@ export const scan = <T, U>(
100113
step: (state: U, value: T) => U,
101114
initial: U
102115
): Signal<U> => {
103-
const { get, [__updates__]: updates, send } = signal(initial)
116+
const { get, [__updates__]: updates, send } = state(initial)
104117
const cancel = sink(upstream, (value: T) => {
105118
send(step(get(), value))
106119
})

0 commit comments

Comments
 (0)