@quenty/rx 7.10.0 → 7.11.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.
- package/CHANGELOG.md +11 -0
- package/package.json +4 -4
- package/src/Shared/Rx.lua +180 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [7.11.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/rx@7.10.0...@quenty/rx@7.11.0) (2023-05-26)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* Add Rx.scan, Rx.reduce, and Rx.throttle ([995a435](https://github.com/Quenty/NevermoreEngine/commit/995a43579ec836c0a300013a2326740f2b14b1d8))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
# [7.10.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/rx@7.9.1...@quenty/rx@7.10.0) (2023-04-10)
|
|
7
18
|
|
|
8
19
|
**Note:** Version bump only for package @quenty/rx
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/rx",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.11.0",
|
|
4
4
|
"description": "Quenty's reactive library for Roblox",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -28,11 +28,11 @@
|
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@quenty/cancellabledelay": "^3.4.0",
|
|
31
|
-
"@quenty/canceltoken": "^6.
|
|
31
|
+
"@quenty/canceltoken": "^6.6.0",
|
|
32
32
|
"@quenty/loader": "^6.2.1",
|
|
33
33
|
"@quenty/maid": "^2.5.0",
|
|
34
34
|
"@quenty/promise": "^6.5.0",
|
|
35
|
-
"@quenty/signal": "^2.
|
|
35
|
+
"@quenty/signal": "^2.4.0",
|
|
36
36
|
"@quenty/symbol": "^2.2.0",
|
|
37
37
|
"@quenty/table": "^3.2.0",
|
|
38
38
|
"@quenty/throttle": "^6.2.1"
|
|
@@ -40,5 +40,5 @@
|
|
|
40
40
|
"publishConfig": {
|
|
41
41
|
"access": "public"
|
|
42
42
|
},
|
|
43
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "11058e90e51ea83d3dad6ae9abe59cc19c36b94b"
|
|
44
44
|
}
|
package/src/Shared/Rx.lua
CHANGED
|
@@ -575,6 +575,81 @@ function Rx.startWith(values)
|
|
|
575
575
|
end
|
|
576
576
|
end
|
|
577
577
|
|
|
578
|
+
--[=[
|
|
579
|
+
The Scan operator applies a function to the first item emitted by the source Observable and then
|
|
580
|
+
emits the result of that function as its own first emission. It also feeds the result of the function
|
|
581
|
+
back into the function along with the second item emitted by the source Observable in order to generate
|
|
582
|
+
its second emission. It continues to feed back its own subsequent emissions along with the subsequent
|
|
583
|
+
emissions from the source Observable in order to create the rest of its sequence.
|
|
584
|
+
|
|
585
|
+
https://reactivex.io/documentation/operators/scan.html
|
|
586
|
+
|
|
587
|
+
@param reducer function
|
|
588
|
+
@param seed any | nil
|
|
589
|
+
@return (source: Observable) -> Observable
|
|
590
|
+
]=]
|
|
591
|
+
function Rx.scan(reducer, seed)
|
|
592
|
+
assert(type(reducer) == "function", "Bad reducer")
|
|
593
|
+
|
|
594
|
+
return function(source)
|
|
595
|
+
assert(Observable.isObservable(source), "Bad observable")
|
|
596
|
+
|
|
597
|
+
return Observable.new(function(sub)
|
|
598
|
+
local maid = Maid.new()
|
|
599
|
+
local current = seed
|
|
600
|
+
|
|
601
|
+
maid:GiveTask(source:Subscribe(
|
|
602
|
+
function(...)
|
|
603
|
+
current = reducer(current, ...)
|
|
604
|
+
sub:Fire(current)
|
|
605
|
+
end,
|
|
606
|
+
sub:GetFailComplete()))
|
|
607
|
+
|
|
608
|
+
return maid
|
|
609
|
+
end)
|
|
610
|
+
end
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
--[=[
|
|
614
|
+
The Reduce operator applies a function to the first item emitted by the source Observable and
|
|
615
|
+
then feeds the result of the function back into the function along with the second item emitted
|
|
616
|
+
by the source Observable, continuing this process until the source Observable emits its final
|
|
617
|
+
item and completes, whereupon the Observable returned from Reduce emits the final value returned
|
|
618
|
+
from the function.
|
|
619
|
+
|
|
620
|
+
https://reactivex.io/documentation/operators/reduce.html
|
|
621
|
+
|
|
622
|
+
@param reducer function
|
|
623
|
+
@param seed any | nil
|
|
624
|
+
@return (source: Observable) -> Observable
|
|
625
|
+
]=]
|
|
626
|
+
function Rx.reduce(reducer, seed)
|
|
627
|
+
assert(type(reducer) == "function", "Bad reducer")
|
|
628
|
+
|
|
629
|
+
return function(source)
|
|
630
|
+
assert(Observable.isObservable(source), "Bad observable")
|
|
631
|
+
|
|
632
|
+
return Observable.new(function(sub)
|
|
633
|
+
local maid = Maid.new()
|
|
634
|
+
local current = seed
|
|
635
|
+
|
|
636
|
+
maid:GiveTask(source:Subscribe(
|
|
637
|
+
function(...)
|
|
638
|
+
current = reducer(current, ...)
|
|
639
|
+
end,
|
|
640
|
+
function(...)
|
|
641
|
+
sub:Fail(...)
|
|
642
|
+
end),
|
|
643
|
+
function()
|
|
644
|
+
-- On complete emit the result.
|
|
645
|
+
sub:Fire(current)
|
|
646
|
+
end)
|
|
647
|
+
|
|
648
|
+
return maid
|
|
649
|
+
end)
|
|
650
|
+
end
|
|
651
|
+
end
|
|
652
|
+
|
|
578
653
|
--[=[
|
|
579
654
|
Defaults the observable to a value if it isn't fired immediately
|
|
580
655
|
|
|
@@ -1010,6 +1085,62 @@ function Rx.flatMap(project, resultSelector)
|
|
|
1010
1085
|
end
|
|
1011
1086
|
end
|
|
1012
1087
|
|
|
1088
|
+
--[=[
|
|
1089
|
+
Switches to a new observable from the current observable
|
|
1090
|
+
|
|
1091
|
+
https://rxjs.dev/api/operators/switchMap
|
|
1092
|
+
|
|
1093
|
+
As each observable shows up, a new observable is mapped from that observable.
|
|
1094
|
+
|
|
1095
|
+
The old observable is disconnected.
|
|
1096
|
+
|
|
1097
|
+
Use Rx.switchMap to switch to a new RunService event
|
|
1098
|
+
|
|
1099
|
+
```lua
|
|
1100
|
+
Rx.of(1, 2, 3):Pipe({
|
|
1101
|
+
Rx.switchMap(function(value)
|
|
1102
|
+
local startTime = os.clock()
|
|
1103
|
+
|
|
1104
|
+
-- Only the last observable returned will continue to emit,
|
|
1105
|
+
-- others are disconnected.
|
|
1106
|
+
return Rx.of(RunService.RenderStepped):Pipe({
|
|
1107
|
+
Rx.map(function()
|
|
1108
|
+
return os.clock() - startTime, value
|
|
1109
|
+
end);
|
|
1110
|
+
});
|
|
1111
|
+
end);
|
|
1112
|
+
}):Subscribe(print) --> 0.002352342, 3
|
|
1113
|
+
```
|
|
1114
|
+
|
|
1115
|
+
Use Rx.switchMap() as a simple map...
|
|
1116
|
+
|
|
1117
|
+
```lua
|
|
1118
|
+
Rx.of(1, 2, 3):Pipe({
|
|
1119
|
+
Rx.switchMap(function(value)
|
|
1120
|
+
print(value) --> 1 (and then 2, and then 3)
|
|
1121
|
+
|
|
1122
|
+
return Rx.of(value*2)
|
|
1123
|
+
end);
|
|
1124
|
+
}):Subscribe(print) --> 2, 4, 6
|
|
1125
|
+
|
|
1126
|
+
```
|
|
1127
|
+
|
|
1128
|
+
Use Rx.switchMap() with delayed input (to swap to a new one)
|
|
1129
|
+
|
|
1130
|
+
```lua
|
|
1131
|
+
Rx.of(1, 2, 3):Pipe({
|
|
1132
|
+
Rx.switchMap(function(value)
|
|
1133
|
+
-- Emit 1 second later
|
|
1134
|
+
return Rx.of(value*2):Pipe({
|
|
1135
|
+
Rx.delay(1); -- These will each get cancelled
|
|
1136
|
+
})
|
|
1137
|
+
end);
|
|
1138
|
+
}):Subscribe(print) --> 6 (other results were cancelled)
|
|
1139
|
+
```
|
|
1140
|
+
|
|
1141
|
+
@param project function
|
|
1142
|
+
@return Observable
|
|
1143
|
+
]=]
|
|
1013
1144
|
function Rx.switchMap(project)
|
|
1014
1145
|
return Rx.pipe({
|
|
1015
1146
|
Rx.map(project);
|
|
@@ -1684,6 +1815,7 @@ function Rx.throttleDefer()
|
|
|
1684
1815
|
end
|
|
1685
1816
|
end)
|
|
1686
1817
|
else
|
|
1818
|
+
|
|
1687
1819
|
lastResult = table.pack(...)
|
|
1688
1820
|
end
|
|
1689
1821
|
end, sub:GetFailComplete()))
|
|
@@ -1693,4 +1825,52 @@ function Rx.throttleDefer()
|
|
|
1693
1825
|
end
|
|
1694
1826
|
end
|
|
1695
1827
|
|
|
1828
|
+
--[=[
|
|
1829
|
+
Throttles emission of observables on the defer stack to the last emission.
|
|
1830
|
+
|
|
1831
|
+
https://rxjs.dev/api/operators/throttle
|
|
1832
|
+
|
|
1833
|
+
@param durationSelector (T: value) -> Observable
|
|
1834
|
+
@return (source: Observable<T>) -> Observable<T>
|
|
1835
|
+
]=]
|
|
1836
|
+
function Rx.throttle(durationSelector)
|
|
1837
|
+
return function(source)
|
|
1838
|
+
assert(Observable.isObservable(source), "Bad observable")
|
|
1839
|
+
|
|
1840
|
+
return Observable.new(function(sub)
|
|
1841
|
+
local topMaid = Maid.new()
|
|
1842
|
+
|
|
1843
|
+
local lastResult
|
|
1844
|
+
|
|
1845
|
+
topMaid:GiveTask(source:Subscribe(function(...)
|
|
1846
|
+
if not lastResult then
|
|
1847
|
+
lastResult = table.pack(...)
|
|
1848
|
+
|
|
1849
|
+
-- Queue up our result
|
|
1850
|
+
local maid = Maid.new()
|
|
1851
|
+
|
|
1852
|
+
maid:GiveTask(durationSelector(lastResult):Subscribe(function()
|
|
1853
|
+
local current = lastResult
|
|
1854
|
+
lastResult = nil
|
|
1855
|
+
|
|
1856
|
+
if sub:IsPending() then
|
|
1857
|
+
sub:Fire(table.unpack(current, 1, current.n))
|
|
1858
|
+
end
|
|
1859
|
+
|
|
1860
|
+
if topMaid._currentQueue == maid then
|
|
1861
|
+
topMaid._currentQueue = nil
|
|
1862
|
+
end
|
|
1863
|
+
end))
|
|
1864
|
+
|
|
1865
|
+
topMaid._currentQueue = maid
|
|
1866
|
+
else
|
|
1867
|
+
lastResult = table.pack(...)
|
|
1868
|
+
end
|
|
1869
|
+
end, sub:GetFailComplete()))
|
|
1870
|
+
|
|
1871
|
+
return topMaid
|
|
1872
|
+
end)
|
|
1873
|
+
end
|
|
1874
|
+
end
|
|
1875
|
+
|
|
1696
1876
|
return Rx
|