@fable-org/fable-library-ts 1.0.0-beta-001
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/Array.ts +1362 -0
- package/Async.ts +207 -0
- package/AsyncBuilder.ts +222 -0
- package/BigInt.ts +337 -0
- package/BitConverter.ts +165 -0
- package/Boolean.ts +22 -0
- package/CHANGELOG.md +15 -0
- package/Char.ts +222 -0
- package/Choice.ts +300 -0
- package/Date.ts +495 -0
- package/DateOffset.ts +324 -0
- package/DateOnly.ts +146 -0
- package/Decimal.ts +250 -0
- package/Double.ts +55 -0
- package/Encoding.ts +170 -0
- package/Event.ts +119 -0
- package/FSharp.Collections.ts +34 -0
- package/FSharp.Core.CompilerServices.ts +37 -0
- package/FSharp.Core.ts +86 -0
- package/Global.ts +37 -0
- package/Guid.ts +143 -0
- package/Int32.ts +156 -0
- package/List.ts +1417 -0
- package/Long.ts +49 -0
- package/MailboxProcessor.ts +125 -0
- package/Map.ts +1552 -0
- package/MapUtil.ts +120 -0
- package/MutableMap.ts +344 -0
- package/MutableSet.ts +248 -0
- package/Native.ts +11 -0
- package/Numeric.ts +80 -0
- package/Observable.ts +156 -0
- package/Option.ts +137 -0
- package/README.md +3 -0
- package/Random.ts +196 -0
- package/Range.ts +56 -0
- package/Reflection.ts +539 -0
- package/RegExp.ts +143 -0
- package/Result.ts +196 -0
- package/Seq.ts +1526 -0
- package/Seq2.ts +129 -0
- package/Set.ts +1955 -0
- package/String.ts +589 -0
- package/System.Collections.Generic.ts +380 -0
- package/System.Text.ts +137 -0
- package/SystemException.ts +7 -0
- package/TimeOnly.ts +131 -0
- package/TimeSpan.ts +194 -0
- package/Timer.ts +80 -0
- package/Types.ts +231 -0
- package/Unicode.13.0.0.ts +4 -0
- package/Uri.ts +206 -0
- package/Util.ts +928 -0
- package/lib/big.d.ts +338 -0
- package/lib/big.js +1054 -0
- package/package.json +24 -0
- package/tsconfig.json +103 -0
package/MutableSet.ts
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { IMap, IEqualityComparer, IDisposable, disposeSafe, defaultOf, ISet, toIterator, IEnumerator, getEnumerator } from "./Util.js";
|
|
2
|
+
import { iterate, map, iterateIndexed, concat } from "./Seq.js";
|
|
3
|
+
import { int32 } from "./Int32.js";
|
|
4
|
+
import { some, Option } from "./Option.js";
|
|
5
|
+
import { FSharpRef } from "./Types.js";
|
|
6
|
+
import { class_type, TypeInfo } from "./Reflection.js";
|
|
7
|
+
import { getItemFromDict, tryGetValue } from "./MapUtil.js";
|
|
8
|
+
|
|
9
|
+
export class HashSet<T> implements ISet<T>, Iterable<T>, Iterable<T> {
|
|
10
|
+
readonly comparer: IEqualityComparer<T>;
|
|
11
|
+
readonly hashMap: IMap<int32, T[]>;
|
|
12
|
+
"init@9": int32;
|
|
13
|
+
constructor(items: Iterable<T>, comparer: IEqualityComparer<T>) {
|
|
14
|
+
const this$: FSharpRef<HashSet<T>> = new FSharpRef<HashSet<T>>(defaultOf());
|
|
15
|
+
this.comparer = comparer;
|
|
16
|
+
this$.contents = this;
|
|
17
|
+
this.hashMap = (new Map<int32, T[]>([]));
|
|
18
|
+
this["init@9"] = 1;
|
|
19
|
+
const enumerator: IEnumerator<T> = getEnumerator(items);
|
|
20
|
+
try {
|
|
21
|
+
while (enumerator["System.Collections.IEnumerator.MoveNext"]()) {
|
|
22
|
+
const item: T = enumerator["System.Collections.Generic.IEnumerator`1.get_Current"]();
|
|
23
|
+
HashSet__Add_2B595<T>(this$.contents, item);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
finally {
|
|
27
|
+
disposeSafe(enumerator as IDisposable);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
get [Symbol.toStringTag](): string {
|
|
31
|
+
return "HashSet";
|
|
32
|
+
}
|
|
33
|
+
toJSON(): any {
|
|
34
|
+
const this$: HashSet<T> = this;
|
|
35
|
+
return Array.from(this$);
|
|
36
|
+
}
|
|
37
|
+
"System.Collections.IEnumerable.GetEnumerator"(): IEnumerator<any> {
|
|
38
|
+
const this$: HashSet<T> = this;
|
|
39
|
+
return getEnumerator(this$);
|
|
40
|
+
}
|
|
41
|
+
GetEnumerator(): IEnumerator<T> {
|
|
42
|
+
const this$: HashSet<T> = this;
|
|
43
|
+
return getEnumerator(concat<T[], T>(this$.hashMap.values()));
|
|
44
|
+
}
|
|
45
|
+
[Symbol.iterator](): Iterator<T> {
|
|
46
|
+
return toIterator(getEnumerator(this));
|
|
47
|
+
}
|
|
48
|
+
"System.Collections.Generic.ICollection`1.Add2B595"(item: T): void {
|
|
49
|
+
const this$: HashSet<T> = this;
|
|
50
|
+
HashSet__Add_2B595<T>(this$, item);
|
|
51
|
+
}
|
|
52
|
+
"System.Collections.Generic.ICollection`1.Clear"(): void {
|
|
53
|
+
const this$: HashSet<T> = this;
|
|
54
|
+
HashSet__Clear<T>(this$);
|
|
55
|
+
}
|
|
56
|
+
"System.Collections.Generic.ICollection`1.Contains2B595"(item: T): boolean {
|
|
57
|
+
const this$: HashSet<T> = this;
|
|
58
|
+
return HashSet__Contains_2B595<T>(this$, item);
|
|
59
|
+
}
|
|
60
|
+
"System.Collections.Generic.ICollection`1.CopyToZ3B4C077E"(array: T[], arrayIndex: int32): void {
|
|
61
|
+
const this$: HashSet<T> = this;
|
|
62
|
+
iterateIndexed<T>((i: int32, e: T): void => {
|
|
63
|
+
array[arrayIndex + i] = e;
|
|
64
|
+
}, this$);
|
|
65
|
+
}
|
|
66
|
+
"System.Collections.Generic.ICollection`1.get_Count"(): int32 {
|
|
67
|
+
const this$: HashSet<T> = this;
|
|
68
|
+
return HashSet__get_Count<T>(this$) | 0;
|
|
69
|
+
}
|
|
70
|
+
"System.Collections.Generic.ICollection`1.get_IsReadOnly"(): boolean {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
"System.Collections.Generic.ICollection`1.Remove2B595"(item: T): boolean {
|
|
74
|
+
const this$: HashSet<T> = this;
|
|
75
|
+
return HashSet__Remove_2B595<T>(this$, item);
|
|
76
|
+
}
|
|
77
|
+
get size(): int32 {
|
|
78
|
+
const this$: HashSet<T> = this;
|
|
79
|
+
return HashSet__get_Count<T>(this$) | 0;
|
|
80
|
+
}
|
|
81
|
+
add(k: T): ISet<T> {
|
|
82
|
+
const this$: HashSet<T> = this;
|
|
83
|
+
HashSet__Add_2B595<T>(this$, k);
|
|
84
|
+
return this$;
|
|
85
|
+
}
|
|
86
|
+
clear(): void {
|
|
87
|
+
const this$: HashSet<T> = this;
|
|
88
|
+
HashSet__Clear<T>(this$);
|
|
89
|
+
}
|
|
90
|
+
delete(k: T): boolean {
|
|
91
|
+
const this$: HashSet<T> = this;
|
|
92
|
+
return HashSet__Remove_2B595<T>(this$, k);
|
|
93
|
+
}
|
|
94
|
+
has(k: T): boolean {
|
|
95
|
+
const this$: HashSet<T> = this;
|
|
96
|
+
return HashSet__Contains_2B595<T>(this$, k);
|
|
97
|
+
}
|
|
98
|
+
keys(): Iterable<T> {
|
|
99
|
+
const this$: HashSet<T> = this;
|
|
100
|
+
return map<T, T>((x: T): T => x, this$);
|
|
101
|
+
}
|
|
102
|
+
values(): Iterable<T> {
|
|
103
|
+
const this$: HashSet<T> = this;
|
|
104
|
+
return map<T, T>((x: T): T => x, this$);
|
|
105
|
+
}
|
|
106
|
+
entries(): Iterable<[T, T]> {
|
|
107
|
+
const this$: HashSet<T> = this;
|
|
108
|
+
return map<T, [T, T]>((v: T): [T, T] => ([v, v] as [T, T]), this$);
|
|
109
|
+
}
|
|
110
|
+
forEach(f: ((arg0: T, arg1: T, arg2: ISet<T>) => void), thisArg?: Option<any>): void {
|
|
111
|
+
const this$: HashSet<T> = this;
|
|
112
|
+
iterate<T>((x: T): void => {
|
|
113
|
+
f(x, x, this$);
|
|
114
|
+
}, this$);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function HashSet_$reflection(gen0: TypeInfo): TypeInfo {
|
|
119
|
+
return class_type("Fable.Collections.HashSet", [gen0], HashSet);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function HashSet_$ctor_Z6150332D<T>(items: Iterable<T>, comparer: IEqualityComparer<T>): HashSet<T> {
|
|
123
|
+
return new HashSet(items, comparer);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function HashSet__TryFindIndex_2B595<T>(this$: HashSet<T>, k: T): [boolean, int32, int32] {
|
|
127
|
+
const h: int32 = this$.comparer.GetHashCode(k) | 0;
|
|
128
|
+
let matchValue: [boolean, T[]];
|
|
129
|
+
let outArg: T[] = defaultOf();
|
|
130
|
+
matchValue = ([tryGetValue(this$.hashMap, h, new FSharpRef<T[]>((): T[] => outArg, (v: T[]): void => {
|
|
131
|
+
outArg = v;
|
|
132
|
+
})), outArg] as [boolean, T[]]);
|
|
133
|
+
if (matchValue[0]) {
|
|
134
|
+
return [true, h, matchValue[1].findIndex((v_1: T): boolean => this$.comparer.Equals(k, v_1))] as [boolean, int32, int32];
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
return [false, h, -1] as [boolean, int32, int32];
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function HashSet__TryFind_2B595<T>(this$: HashSet<T>, k: T): Option<T> {
|
|
142
|
+
const matchValue: [boolean, int32, int32] = HashSet__TryFindIndex_2B595<T>(this$, k);
|
|
143
|
+
let matchResult: int32;
|
|
144
|
+
if (matchValue[0]) {
|
|
145
|
+
if (matchValue[2] > -1) {
|
|
146
|
+
matchResult = 0;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
matchResult = 1;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
matchResult = 1;
|
|
154
|
+
}
|
|
155
|
+
switch (matchResult) {
|
|
156
|
+
case 0:
|
|
157
|
+
return some(getItemFromDict(this$.hashMap, matchValue[1])[matchValue[2]]);
|
|
158
|
+
default:
|
|
159
|
+
return void 0;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function HashSet__get_Comparer<T>(this$: HashSet<T>): IEqualityComparer<T> {
|
|
164
|
+
return this$.comparer;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function HashSet__Clear<T>(this$: HashSet<T>): void {
|
|
168
|
+
this$.hashMap.clear();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export function HashSet__get_Count<T>(this$: HashSet<T>): int32 {
|
|
172
|
+
let count = 0;
|
|
173
|
+
let enumerator: any = getEnumerator(this$.hashMap.values());
|
|
174
|
+
try {
|
|
175
|
+
while (enumerator["System.Collections.IEnumerator.MoveNext"]()) {
|
|
176
|
+
const items: T[] = enumerator["System.Collections.Generic.IEnumerator`1.get_Current"]();
|
|
177
|
+
count = ((count + items.length) | 0);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
finally {
|
|
181
|
+
disposeSafe(enumerator);
|
|
182
|
+
}
|
|
183
|
+
return count | 0;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export function HashSet__Add_2B595<T>(this$: HashSet<T>, k: T): boolean {
|
|
187
|
+
const matchValue: [boolean, int32, int32] = HashSet__TryFindIndex_2B595<T>(this$, k);
|
|
188
|
+
if (matchValue[0]) {
|
|
189
|
+
if (matchValue[2] > -1) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
const value: any = void (getItemFromDict(this$.hashMap, matchValue[1]).push(k));
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
this$.hashMap.set(matchValue[1], [k]);
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export function HashSet__Contains_2B595<T>(this$: HashSet<T>, k: T): boolean {
|
|
204
|
+
const matchValue: [boolean, int32, int32] = HashSet__TryFindIndex_2B595<T>(this$, k);
|
|
205
|
+
let matchResult: int32;
|
|
206
|
+
if (matchValue[0]) {
|
|
207
|
+
if (matchValue[2] > -1) {
|
|
208
|
+
matchResult = 0;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
matchResult = 1;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
matchResult = 1;
|
|
216
|
+
}
|
|
217
|
+
switch (matchResult) {
|
|
218
|
+
case 0:
|
|
219
|
+
return true;
|
|
220
|
+
default:
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export function HashSet__Remove_2B595<T>(this$: HashSet<T>, k: T): boolean {
|
|
226
|
+
const matchValue: [boolean, int32, int32] = HashSet__TryFindIndex_2B595<T>(this$, k);
|
|
227
|
+
let matchResult: int32;
|
|
228
|
+
if (matchValue[0]) {
|
|
229
|
+
if (matchValue[2] > -1) {
|
|
230
|
+
matchResult = 0;
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
matchResult = 1;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
matchResult = 1;
|
|
238
|
+
}
|
|
239
|
+
switch (matchResult) {
|
|
240
|
+
case 0: {
|
|
241
|
+
getItemFromDict(this$.hashMap, matchValue[1]).splice(matchValue[2], 1);
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
default:
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
package/Native.ts
ADDED
package/Numeric.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { IComparable } from "./Util.js";
|
|
2
|
+
|
|
3
|
+
export const symbol = Symbol("numeric");
|
|
4
|
+
|
|
5
|
+
export interface CustomNumeric extends IComparable<Numeric> {
|
|
6
|
+
[symbol](): {
|
|
7
|
+
multiply(y: Numeric): Numeric,
|
|
8
|
+
toPrecision(sd?: number): string,
|
|
9
|
+
toExponential(dp?: number): string,
|
|
10
|
+
toFixed(dp?: number): string,
|
|
11
|
+
toHex(): string,
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type Numeric = number | bigint | CustomNumeric;
|
|
16
|
+
|
|
17
|
+
export function isNumeric(x: any) {
|
|
18
|
+
return typeof x === "number" || typeof x === "bigint" || x?.[symbol];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function compare(x: Numeric, y: number) {
|
|
22
|
+
if (typeof x === "number") {
|
|
23
|
+
return x < y ? -1 : (x > y ? 1 : 0);
|
|
24
|
+
} else if (typeof x === "bigint") {
|
|
25
|
+
return x < y ? -1 : (x > y ? 1 : 0);
|
|
26
|
+
} else {
|
|
27
|
+
return x.CompareTo(y);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function multiply(x: Numeric, y: number) {
|
|
32
|
+
if (typeof x === "number") {
|
|
33
|
+
return x * y;
|
|
34
|
+
} else if (typeof x === "bigint") {
|
|
35
|
+
return x * BigInt(y);
|
|
36
|
+
} else {
|
|
37
|
+
return x[symbol]().multiply(y);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function toFixed(x: Numeric, dp?: number) {
|
|
42
|
+
if (typeof x === "number") {
|
|
43
|
+
return x.toFixed(dp);
|
|
44
|
+
} else if (typeof x === "bigint") {
|
|
45
|
+
return x;
|
|
46
|
+
} else {
|
|
47
|
+
return x[symbol]().toFixed(dp);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function toPrecision(x: Numeric, sd?: number) {
|
|
52
|
+
if (typeof x === "number") {
|
|
53
|
+
return x.toPrecision(sd);
|
|
54
|
+
} else if (typeof x === "bigint") {
|
|
55
|
+
return x;
|
|
56
|
+
} else {
|
|
57
|
+
return x[symbol]().toPrecision(sd);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function toExponential(x: Numeric, dp?: number) {
|
|
62
|
+
if (typeof x === "number") {
|
|
63
|
+
return x.toExponential(dp);
|
|
64
|
+
} else if (typeof x === "bigint") {
|
|
65
|
+
return x;
|
|
66
|
+
} else {
|
|
67
|
+
return x[symbol]().toExponential(dp);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function toHex(x: Numeric) {
|
|
72
|
+
if (typeof x === "number") {
|
|
73
|
+
return (Number(x) >>> 0).toString(16);
|
|
74
|
+
} else if (typeof x === "bigint") {
|
|
75
|
+
// TODO: properly handle other bit sizes
|
|
76
|
+
return BigInt.asUintN(64, x).toString(16);
|
|
77
|
+
} else {
|
|
78
|
+
return x[symbol]().toHex();
|
|
79
|
+
}
|
|
80
|
+
}
|
package/Observable.ts
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
|
|
2
|
+
import { FSharpChoice$2_$union, Choice_tryValueIfChoice1Of2, Choice_tryValueIfChoice2Of2 } from "./Choice.js";
|
|
3
|
+
import { Option, value } from "./Option.js";
|
|
4
|
+
import { IDisposable } from "./Util.js";
|
|
5
|
+
|
|
6
|
+
export interface IObserver<T> {
|
|
7
|
+
OnNext: (x: T) => void;
|
|
8
|
+
OnError: (e: any) => void;
|
|
9
|
+
OnCompleted: () => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class Observer<T> implements IObserver<T> {
|
|
13
|
+
public OnNext: (x: T) => void;
|
|
14
|
+
public OnError: (e: any) => void;
|
|
15
|
+
public OnCompleted: () => void;
|
|
16
|
+
|
|
17
|
+
constructor(onNext: (x: T) => void, onError?: (e: any) => void, onCompleted?: () => void) {
|
|
18
|
+
this.OnNext = onNext;
|
|
19
|
+
this.OnError = onError || ((_e: any) => { return; });
|
|
20
|
+
this.OnCompleted = onCompleted || (() => { return; });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface IObservable<T> {
|
|
25
|
+
Subscribe: (o: IObserver<T>) => IDisposable;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
class Observable<T> implements IObservable<T> {
|
|
29
|
+
public Subscribe: (o: IObserver<T>) => IDisposable;
|
|
30
|
+
|
|
31
|
+
constructor(subscribe: (o: IObserver<T>) => IDisposable) {
|
|
32
|
+
this.Subscribe = subscribe;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function protect<T>(f: () => T, succeed: (x: T) => void, fail: (e: any) => void) {
|
|
37
|
+
try {
|
|
38
|
+
return succeed(f());
|
|
39
|
+
} catch (e) {
|
|
40
|
+
fail(e);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function add<T>(callback: (x: T) => void, source: IObservable<T>): void {
|
|
45
|
+
source.Subscribe(new Observer(callback));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function choose<T, U>(chooser: (x: T) => Option<U>, source: IObservable<T>): Observable<U> {
|
|
49
|
+
return new Observable<U>((observer) =>
|
|
50
|
+
source.Subscribe(new Observer<T>((t) =>
|
|
51
|
+
protect(
|
|
52
|
+
() => chooser(t),
|
|
53
|
+
(u) => { if (u != null) { observer.OnNext(value(u)); } },
|
|
54
|
+
observer.OnError),
|
|
55
|
+
observer.OnError, observer.OnCompleted)));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function filter<T>(predicate: (x: T) => boolean, source: IObservable<T>): IObservable<T> {
|
|
59
|
+
return choose((x) => predicate(x) ? x : void 0, source);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function map<T, U>(mapping: (x: T) => U, source: IObservable<T>): IObservable<U> {
|
|
63
|
+
return new Observable<U>((observer) =>
|
|
64
|
+
source.Subscribe(new Observer<T>((t) => {
|
|
65
|
+
protect(
|
|
66
|
+
() => mapping(t),
|
|
67
|
+
observer.OnNext,
|
|
68
|
+
observer.OnError);
|
|
69
|
+
}, observer.OnError, observer.OnCompleted)));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function merge<T>(source1: IObservable<T>, source2: IObservable<T>): IObservable<T> {
|
|
73
|
+
return new Observable((observer) => {
|
|
74
|
+
let stopped = false;
|
|
75
|
+
let completed1 = false;
|
|
76
|
+
let completed2 = false;
|
|
77
|
+
const h1 = source1.Subscribe(new Observer<T>(
|
|
78
|
+
(v) => { if (!stopped) { observer.OnNext(v); } },
|
|
79
|
+
(e) => {
|
|
80
|
+
if (!stopped) {
|
|
81
|
+
stopped = true;
|
|
82
|
+
observer.OnError(e);
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
() => {
|
|
86
|
+
if (!stopped) {
|
|
87
|
+
completed1 = true;
|
|
88
|
+
if (completed2) {
|
|
89
|
+
stopped = true;
|
|
90
|
+
observer.OnCompleted();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}));
|
|
94
|
+
const h2 = source2.Subscribe(new Observer<T>(
|
|
95
|
+
(v) => { if (!stopped) { observer.OnNext(v); } },
|
|
96
|
+
(e) => {
|
|
97
|
+
if (!stopped) {
|
|
98
|
+
stopped = true;
|
|
99
|
+
observer.OnError(e);
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
() => {
|
|
103
|
+
if (!stopped) {
|
|
104
|
+
completed2 = true;
|
|
105
|
+
if (completed1) {
|
|
106
|
+
stopped = true;
|
|
107
|
+
observer.OnCompleted();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}));
|
|
111
|
+
return {
|
|
112
|
+
Dispose() {
|
|
113
|
+
h1.Dispose();
|
|
114
|
+
h2.Dispose();
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function pairwise<T>(source: IObservable<T>): IObservable<[T, T]> {
|
|
121
|
+
return new Observable<[T, T]>((observer) => {
|
|
122
|
+
let last: T;
|
|
123
|
+
return source.Subscribe(new Observer<T>((next) => {
|
|
124
|
+
if (last != null) {
|
|
125
|
+
observer.OnNext([last, next]);
|
|
126
|
+
}
|
|
127
|
+
last = next;
|
|
128
|
+
}, observer.OnError, observer.OnCompleted));
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function partition<T>(predicate: (x: T) => boolean, source: IObservable<T>): [Observable<T>, Observable<T>] {
|
|
133
|
+
return [filter(predicate, source), filter((x) => !predicate(x), source)];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function scan<U, T>(collector: (u: U, t: T) => U, state: U, source: IObservable<T>): IObservable<U> {
|
|
137
|
+
return new Observable<U>((observer) => {
|
|
138
|
+
return source.Subscribe(new Observer<T>((t) => {
|
|
139
|
+
protect(
|
|
140
|
+
() => collector(state, t),
|
|
141
|
+
(u) => { state = u; observer.OnNext(u); },
|
|
142
|
+
observer.OnError);
|
|
143
|
+
}, observer.OnError, observer.OnCompleted));
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function split<T, U1, U2>(splitter: (x: T) => FSharpChoice$2_$union<U1, U2>, source: IObservable<T>): [Observable<U1>, Observable<U2>] {
|
|
148
|
+
return [
|
|
149
|
+
choose((v) => Choice_tryValueIfChoice1Of2(splitter(v)), source),
|
|
150
|
+
choose((v) => Choice_tryValueIfChoice2Of2(splitter(v)), source)
|
|
151
|
+
];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function subscribe<T>(callback: (x: T) => void, source: IObservable<T>): IDisposable {
|
|
155
|
+
return source.Subscribe(new Observer(callback));
|
|
156
|
+
}
|
package/Option.ts
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { structuralHash, equals, compare } from "./Util.js";
|
|
2
|
+
|
|
3
|
+
// Options are erased in runtime by Fable, but we have
|
|
4
|
+
// the `Some` type below to wrap values that would evaluate
|
|
5
|
+
// to `undefined` in runtime. These two rules must be followed:
|
|
6
|
+
|
|
7
|
+
// 1- `None` is always `undefined` in runtime, a non-strict null check
|
|
8
|
+
// (`x == null`) is enough to check the case of an option.
|
|
9
|
+
// 2- To get the value of an option the `value` helper
|
|
10
|
+
// below must **always** be used.
|
|
11
|
+
|
|
12
|
+
// Note: We use non-strict null check for backwards compatibility with
|
|
13
|
+
// code that use F# options to represent values that could be null in JS
|
|
14
|
+
|
|
15
|
+
export type Nullable<T> = T | null | undefined;
|
|
16
|
+
|
|
17
|
+
export type Option<T> = T | Some<T> | undefined;
|
|
18
|
+
|
|
19
|
+
// Using a class here for better compatibility with TS files importing Some
|
|
20
|
+
export class Some<T> {
|
|
21
|
+
public value: T;
|
|
22
|
+
|
|
23
|
+
constructor(value: T) {
|
|
24
|
+
this.value = value;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public toJSON() {
|
|
28
|
+
return this.value;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Don't add "Some" for consistency with erased options
|
|
32
|
+
public toString() {
|
|
33
|
+
return String(this.value);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public GetHashCode() {
|
|
37
|
+
return structuralHash(this.value);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public Equals(other: Option<T>): boolean {
|
|
41
|
+
if (other == null) {
|
|
42
|
+
return false;
|
|
43
|
+
} else {
|
|
44
|
+
return equals(this.value, other instanceof Some ? other.value : other);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public CompareTo(other: Option<T>) {
|
|
49
|
+
if (other == null) {
|
|
50
|
+
return 1;
|
|
51
|
+
} else {
|
|
52
|
+
return compare(this.value, other instanceof Some ? other.value : other);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function value<T>(x: Option<T>) {
|
|
58
|
+
if (x == null) {
|
|
59
|
+
throw new Error("Option has no value");
|
|
60
|
+
} else {
|
|
61
|
+
return x instanceof Some ? x.value : x;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function unwrap<T>(opt: Option<T>): T | undefined {
|
|
66
|
+
return opt instanceof Some ? opt.value : opt;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function some<T>(x: T): Option<T> {
|
|
70
|
+
return x == null || x instanceof Some ? new Some(x) : x;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function ofNullable<T>(x: Nullable<T>): Option<T> {
|
|
74
|
+
// This will fail with unit probably, an alternative would be:
|
|
75
|
+
// return x === null ? undefined : (x === undefined ? new Some(x) : x);
|
|
76
|
+
return x == null ? undefined : x;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function toNullable<T>(x: Option<T>): Nullable<T> {
|
|
80
|
+
return x == null ? null : value(x);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function flatten<T>(x: Option<Option<T>>) {
|
|
84
|
+
return x == null ? undefined : value(x);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function toArray<T>(opt: Option<T>): T[] {
|
|
88
|
+
return (opt == null) ? [] : [value(opt)];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function defaultArg<T>(opt: Option<T>, defaultValue: T): T {
|
|
92
|
+
return (opt != null) ? value(opt) : defaultValue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function defaultArgWith<T>(opt: Option<T>, defThunk: () => T): T {
|
|
96
|
+
return (opt != null) ? value(opt) : defThunk();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function orElse<T>(opt: Option<T>, ifNone: Option<T>): Option<T> {
|
|
100
|
+
return opt == null ? ifNone : opt;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function orElseWith<T>(opt: Option<T>, ifNoneThunk: () => Option<T>): Option<T> {
|
|
104
|
+
return opt == null ? ifNoneThunk() : opt;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function filter<T>(predicate: (arg: T) => boolean, opt: Option<T>): Option<T> {
|
|
108
|
+
return (opt != null) ? (predicate(value(opt)) ? opt : undefined) : opt;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function map<T, U>(mapping: (arg: T) => U, opt: Option<T>): Option<U> {
|
|
112
|
+
return (opt != null) ? some(mapping(value(opt))) : undefined;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function map2<T1, T2, U>(
|
|
116
|
+
mapping: (arg1: T1, arg2: T2) => Option<U>,
|
|
117
|
+
opt1: Option<T1>, opt2: Option<T2>): Option<U> {
|
|
118
|
+
return (opt1 != null && opt2 != null) ? mapping(value(opt1), value(opt2)) : undefined;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function map3<T1, T2, T3, U>(
|
|
122
|
+
mapping: (arg1: T1, arg2: T2, arg3: T3) => Option<U>,
|
|
123
|
+
opt1: Option<T1>, opt2: Option<T2>, opt3: Option<T3>): Option<U> {
|
|
124
|
+
return (opt1 != null && opt2 != null && opt3 != null) ? mapping(value(opt1), value(opt2), value(opt3)) : undefined;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function bind<T, U>(binder: (arg: T) => Option<U>, opt: Option<T>): Option<U> {
|
|
128
|
+
return opt != null ? binder(value(opt)) : undefined;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function tryOp<T, U>(op: (x: T) => U, arg: T): Option<U> {
|
|
132
|
+
try {
|
|
133
|
+
return some(op(arg));
|
|
134
|
+
} catch {
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
}
|
package/README.md
ADDED