@fable-org/fable-library-js 2.9.0 → 2.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/Async.js CHANGED
@@ -2,8 +2,8 @@ import { OperationCanceledException, Trampoline } from "./AsyncBuilder.js";
2
2
  import { CancellationToken } from "./AsyncBuilder.js";
3
3
  import { protectedCont, protectedBind, protectedReturn } from "./AsyncBuilder.js";
4
4
  import { Choice_makeChoice1Of2, Choice_makeChoice2Of2 } from "./Choice.js";
5
- import { InvalidOperationException_$ctor_Z721C83C5, TimeoutException_$ctor } from "./System.js";
6
- import { Exception } from "./Util.js";
5
+ import { ArgumentException_$ctor_Z384F8060, InvalidOperationException_$ctor_Z721C83C5, TimeoutException_$ctor } from "./System.js";
6
+ import { Exception, ensureErrorOrException } from "./Util.js";
7
7
  function emptyContinuation(_x) {
8
8
  // NOP
9
9
  }
@@ -44,27 +44,43 @@ export function throwIfCancellationRequested(token) {
44
44
  throw new Exception("Operation is cancelled");
45
45
  }
46
46
  }
47
+ // The parent keeps the listener until unlink is called
48
+ function createLinkedToken(parent) {
49
+ const token = new CancellationToken();
50
+ const id = parent.addListener(() => token.cancel());
51
+ return [token, () => { parent.removeListener(id); }];
52
+ }
47
53
  export function startChild(computation, ms) {
48
54
  return protectedCont((ctx) => {
49
- // Share the parent's cancellation token so cancelling the parent
50
- // cancels the child, like .NET Async.StartChild
51
- const promise = startAsPromise(computation, ctx.cancelToken);
52
- let promiseToRun = promise;
53
- if (ms) {
54
- // Race the computation against a timeout: whichever settles first wins.
55
- promiseToRun = new Promise((resolve, reject) => {
56
- const timeoutId = setTimeout(() => reject(TimeoutException_$ctor()), ms);
57
- promise.then(value => { clearTimeout(timeoutId); resolve(value); }, error => { clearTimeout(timeoutId); reject(error); });
58
- });
59
- }
60
- // Prevent an unhandled rejection when the child is cancelled or fails
61
- // while nobody awaits it (in F# an unobserved child's cancellation or
62
- // failure is simply not propagated). awaitPromise attaches its own
63
- // handlers to the same promise, so awaiting still observes the result.
64
- promiseToRun.catch(emptyContinuation);
55
+ const timeout = ms == null || ms === -1 ? undefined : ms;
56
+ const [childToken, unlink] = timeout === undefined
57
+ ? [ctx.cancelToken, () => { }]
58
+ : createLinkedToken(ctx.cancelToken);
59
+ const promise = startAsPromise(computation, childToken);
60
+ let settled = false;
61
+ const onSettled = () => { settled = true; unlink(); };
62
+ // Without a rejection handler an unawaited child's failure is an unhandled rejection
63
+ promise.then(onSettled, onSettled);
64
+ // Like .NET, the timeout only runs while the result is awaited, not from the start of the child
65
+ const awaitResult = () => timeout === undefined || settled ? promise : new Promise((resolve, reject) => {
66
+ const timeoutId = setTimeout(() => {
67
+ // .NET doesn't cancel the child when the timeout is 0
68
+ if (timeout !== 0) {
69
+ try {
70
+ childToken.cancel();
71
+ }
72
+ catch (error) {
73
+ reject(error);
74
+ return;
75
+ }
76
+ }
77
+ reject(TimeoutException_$ctor());
78
+ }, timeout);
79
+ promise.then(value => { clearTimeout(timeoutId); resolve(value); }, error => { clearTimeout(timeoutId); reject(error); });
80
+ });
65
81
  // JS Promises are hot, computation has already started
66
82
  // but we delay returning the result
67
- protectedReturn(awaitPromise(promiseToRun))(ctx);
83
+ protectedReturn(protectedCont((awaitCtx) => awaitPromise(awaitResult())(awaitCtx)))(ctx);
68
84
  });
69
85
  }
70
86
  export function awaitPromise(p) {
@@ -154,9 +170,132 @@ export function fromContinuations(f) {
154
170
  export function ignore(computation) {
155
171
  return protectedBind(computation, (_x) => protectedReturn(void 0));
156
172
  }
157
- export function parallel(computations) {
158
- // Children share the parent's cancellation token, like .NET Async.Parallel
159
- return protectedCont((ctx) => awaitPromise(Promise.all(Array.from(computations, (w) => startAsPromise(w, ctx.cancelToken))))(ctx));
173
+ export function parallel(computations, maxDegreeOfParallelism) {
174
+ if (maxDegreeOfParallelism != null && maxDegreeOfParallelism < 1) {
175
+ throw ArgumentException_$ctor_Z384F8060(`maxDegreeOfParallelism must be positive, was ${maxDegreeOfParallelism}`, "maxDegreeOfParallelism");
176
+ }
177
+ return protectedCont((ctx) => awaitPromise(runParallel(Array.from(computations), maxDegreeOfParallelism, ctx.cancelToken))(ctx));
178
+ }
179
+ function runParallel(computations, limit, parentToken) {
180
+ return new Promise((resolve, reject) => {
181
+ const count = computations.length;
182
+ const results = new Array(count);
183
+ const [token, unlink] = createLinkedToken(parentToken);
184
+ let next = 0;
185
+ let running = 0;
186
+ let failed = false;
187
+ let failure;
188
+ const startNext = () => {
189
+ const i = next++;
190
+ running++;
191
+ startAsPromise(computations[i], token)
192
+ .then((x) => { results[i] = x; }, (err) => {
193
+ if (!failed) {
194
+ failed = true;
195
+ failure = err;
196
+ try {
197
+ token.cancel();
198
+ }
199
+ catch (error) {
200
+ failure = error;
201
+ }
202
+ }
203
+ })
204
+ .then(() => {
205
+ running--;
206
+ if (!failed && next < count) {
207
+ startNext();
208
+ }
209
+ else if (running === 0) {
210
+ unlink();
211
+ if (failed) {
212
+ reject(failure);
213
+ }
214
+ else {
215
+ resolve(results);
216
+ }
217
+ }
218
+ });
219
+ };
220
+ if (count === 0) {
221
+ unlink();
222
+ resolve(results);
223
+ }
224
+ const initial = Math.min(limit ?? count, count);
225
+ while (next < initial) {
226
+ startNext();
227
+ }
228
+ });
229
+ }
230
+ export function choice(computations) {
231
+ return protectedCont((ctx) => {
232
+ const works = Array.from(computations);
233
+ let remaining = works.length;
234
+ if (remaining === 0) {
235
+ ctx.onSuccess(undefined);
236
+ return;
237
+ }
238
+ const [token, unlink] = createLinkedToken(ctx.cancelToken);
239
+ let done = false;
240
+ const finish = (report) => {
241
+ if (done) {
242
+ return;
243
+ }
244
+ done = true;
245
+ unlink();
246
+ try {
247
+ token.cancel();
248
+ }
249
+ catch (error) {
250
+ ctx.onError(ensureErrorOrException(error));
251
+ return;
252
+ }
253
+ report();
254
+ };
255
+ for (const work of works) {
256
+ startWithContinuations(work, (x) => {
257
+ if (x != null) {
258
+ finish(() => ctx.onSuccess(x));
259
+ }
260
+ else if (--remaining === 0) {
261
+ finish(() => ctx.onSuccess(undefined));
262
+ }
263
+ }, (err) => finish(() => ctx.onError(err)), (err) => finish(() => ctx.onCancel(err)), token);
264
+ if (done) {
265
+ break;
266
+ }
267
+ }
268
+ });
269
+ }
270
+ export function onCancel(interruption) {
271
+ return protectedCont((ctx) => {
272
+ const token = ctx.cancelToken;
273
+ let interrupted = false;
274
+ const interrupt = () => {
275
+ if (!interrupted) {
276
+ interrupted = true;
277
+ try {
278
+ interruption();
279
+ }
280
+ catch { /* Ignored, like .NET Async.OnCancel */ }
281
+ }
282
+ };
283
+ const id = token.addListener(interrupt);
284
+ let disposed = false;
285
+ ctx.onSuccess({
286
+ Dispose() {
287
+ if (disposed) {
288
+ return;
289
+ }
290
+ disposed = true;
291
+ token.removeListener(id);
292
+ // With use! Dispose runs inside cancel() before this listener gets its turn
293
+ if (token.isCancelled) {
294
+ interrupt();
295
+ }
296
+ },
297
+ });
298
+ });
160
299
  }
161
300
  export function sequential(computations) {
162
301
  function _sequential(computations, cancelToken) {
@@ -216,3 +355,9 @@ export function startWithContinuations(computation, continuation, exceptionConti
216
355
  export function startAsPromise(computation, cancellationToken) {
217
356
  return new Promise((resolve, reject) => startWithContinuations(computation, resolve, reject, reject, cancellationToken ? cancellationToken : defaultCancellationToken));
218
357
  }
358
+ export function startAsTask(computation, _taskCreationOptions, cancellationToken) {
359
+ return startAsPromise(computation, cancellationToken);
360
+ }
361
+ export function startImmediateAsTask(computation, cancellationToken) {
362
+ return startAsPromise(computation, cancellationToken);
363
+ }
package/BigInt.js CHANGED
@@ -1,5 +1,7 @@
1
+ import { FSharpRef } from "./Types.js";
1
2
  import { fromParts, truncate } from "./Decimal.js";
2
3
  import { Exception, bigintHash } from "./Util.js";
4
+ import { ArgumentNullException_$ctor_Z721C83C5, FormatException_$ctor_Z721C83C5 } from "./System.js";
3
5
  const isBigEndian = false;
4
6
  BigInt.prototype.toJSON = function () {
5
7
  return `${this.toString()}`;
@@ -151,17 +153,27 @@ export function toChar(x) {
151
153
  return String.fromCharCode(toUInt16(x));
152
154
  }
153
155
  export function toString(x) { return x.toString(); }
156
+ // .NET's Integer style: white space, a sign and decimal digits, then NULs
157
+ const integerRegex = /^[\t-\r ]*([+-]?\d+)[\t-\r ]*\0*$/;
154
158
  export function tryParse(s, res) {
155
- try {
156
- res.contents = BigInt(s);
159
+ const m = s == null ? null : integerRegex.exec(s);
160
+ if (m != null) {
161
+ res.contents = BigInt(m[1]);
157
162
  return true;
158
163
  }
159
- catch (err) {
160
- return false;
161
- }
164
+ return false;
162
165
  }
163
166
  export function parse(s) {
164
- return BigInt(s);
167
+ const res = new FSharpRef(zero);
168
+ if (tryParse(s, res)) {
169
+ return res.contents;
170
+ }
171
+ else if (s == null) {
172
+ throw ArgumentNullException_$ctor_Z721C83C5("value");
173
+ }
174
+ else {
175
+ throw FormatException_$ctor_Z721C83C5("The value could not be parsed.");
176
+ }
165
177
  }
166
178
  export function pow(x, n) {
167
179
  return x ** BigInt(n);
package/CHANGELOG.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- last_commit_released: e33c57870454fea189a3eb33519f583a5003f8c3
2
+ last_commit_released: ce886964cb4521dc4c01c8da089b97c9d9742814
3
3
  updaters:
4
4
  - package.json:
5
5
  file: package.json
@@ -15,6 +15,57 @@ All notable changes to this project will be documented in this file.
15
15
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
16
16
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
17
17
 
18
+ ## 2.11.0 - 2026-10-29
19
+
20
+ ### 🚀 Features
21
+
22
+ * *(js/ts/python/dart/beam)* Support System.Array.BinarySearch and ResizeArray.BinarySearch (#5172) ([d332e7d4](https://github.com/fable-compiler/Fable/commit/d332e7d42c889f172bb9501f505292abf519752f))
23
+
24
+ ### 🐞 Bug Fixes
25
+
26
+ * *(all)* Accept RegexOptions.NonBacktracking (#5178) ([a61ec8a1](https://github.com/fable-compiler/Fable/commit/a61ec8a1583830599a7ffb2dfb4d093e99902d4f))
27
+ * *(js/ts)* Format DateTimeOffset in its own offset (#5171) ([04ddbd20](https://github.com/fable-compiler/Fable/commit/04ddbd2027e03f4cf7b0b22fe886fdabadf26d93))
28
+ * *(js/ts)* Support %o in sprintf and interpolated strings (#5175) ([e13e7b0f](https://github.com/fable-compiler/Fable/commit/e13e7b0fdc16d26793833c77a11d242ccc61109b))
29
+ * *(js/ts)* Parse numbers like .NET and raise its exception types (#5200) ([82e606e9](https://github.com/fable-compiler/Fable/commit/82e606e9f8567d9bdad743df1b5de6abbdda89b0))
30
+ * *(js/ts)* Honor NumberStyles when parsing floats (#5217) ([82b935f3](https://github.com/fable-compiler/Fable/commit/82b935f3859b36923e5e0eb26771f860eadbe525))
31
+ * *(js/ts/python/dart/beam)* Raise typed exceptions from invalidArg and invalidOp ([60f2f5b9](https://github.com/fable-compiler/Fable/commit/60f2f5b9fa0e6a26af0f3b4f3cddc2496f075ba3))
32
+ * *(js/ts/python/dart/beam)* Align collection exception types with FSharp.Core (#5153) ([7d7ceb33](https://github.com/fable-compiler/Fable/commit/7d7ceb33afd85a25bf06dc703e9d4a471cbc3292))
33
+ * *(js/ts/python/dart/beam)* Add FSharp.Core's argument checks to collection functions (#5154) ([5185e654](https://github.com/fable-compiler/Fable/commit/5185e6547416384fe85fcb0b0c1cf267708879db))
34
+
35
+ ### ⚡ Performance Improvements
36
+
37
+ * *(js/ts)* Standard library combine numeric hash from snapshot of object instead of mapping (#5151) ([44495104](https://github.com/fable-compiler/Fable/commit/44495104b5c7ac65bfcea184d1305fd29f1db9b4))
38
+ * *(js/ts)* Standard library remove .map result array from record hash using snapshot (#5150) ([0ceb5e9e](https://github.com/fable-compiler/Fable/commit/0ceb5e9ec5b470d00295a5cea9ead1c621c7858e))
39
+ * *(js/ts)* Standard library one pass List.append builder (#5148) ([2ed9d6dd](https://github.com/fable-compiler/Fable/commit/2ed9d6dd0a372e5bcf53dfe24d786bf9b9256fd3))
40
+ * *(js/ts)* List node as a class with a shared empty node (#5185) ([187f8985](https://github.com/fable-compiler/Fable/commit/187f89852413186b52d4ecdde55e1be7cf736785))
41
+ * *(js/ts)* Check array bounds only on undefined reads (#5188) ([435fc0bb](https://github.com/fable-compiler/Fable/commit/435fc0bb008ff2ab7c14a08c7218be94f4735029))
42
+ * *(js/ts)* Closure-free ref cells and out-arg value cells (#5189) ([91bca925](https://github.com/fable-compiler/Fable/commit/91bca925757356191c7e6e7a71cb3e8a1bc8d52d))
43
+ * *(js/ts)* Keep the curried original on its adapter (#5191) ([bfb4a2a4](https://github.com/fable-compiler/Fable/commit/bfb4a2a4e3bb1b5bd4491955a1e1cb90c14050b6))
44
+ * *(js/ts)* Walk arrays by index when enumerated as seq (#5192) ([d88621c3](https://github.com/fable-compiler/Fable/commit/d88621c3b9d6ce48a72dc09b86a6805f612ac185))
45
+ * *(js/ts)* Hash unions without allocating (#5195) ([2b66a5d2](https://github.com/fable-compiler/Fable/commit/2b66a5d2184f3a35f0d73fb397ab902e300ac4bd))
46
+ * *(js/ts)* Probe dictionary buckets without allocating (#5196) ([9517eafd](https://github.com/fable-compiler/Fable/commit/9517eafd93aa7b84061662a421b7a39a7269318b))
47
+
48
+ <strong><small>[View changes on Github](https://github.com/fable-compiler/Fable/compare/2098f64a25e96385306ef19ed8c289f3b6c84db9..ce886964cb4521dc4c01c8da089b97c9d9742814)</small></strong>
49
+
50
+ ## 2.10.0 - 2026-10-22
51
+
52
+ ### 🚀 Features
53
+
54
+ * *(js/ts)* Support System.Diagnostics.Stopwatch (#5100) ([eb68225f](https://github.com/fable-compiler/Fable/commit/eb68225ff74d1b455765d99998faa6fd3be32383))
55
+
56
+ ### 🐞 Bug Fixes
57
+
58
+ * *(js/ts)* Round decimals below 0.1 correctly ([fca4c408](https://github.com/fable-compiler/Fable/commit/fca4c408a64e33c58293f12869975e5b61bcb96a))
59
+ * *(js/ts)* Keep decimal zero scale without leading zeros ([3076b45a](https://github.com/fable-compiler/Fable/commit/3076b45acacf39b8c99ec57025560ad355ab74db))
60
+ * *(js/ts)* Hash decimals by value in collections ([32a69e0d](https://github.com/fable-compiler/Fable/commit/32a69e0d00f567c9a838307e9ed51b3b1d519473))
61
+ * *(js/ts)* Keep .NET decimal scale through arithmetic (#5126) ([bdf0a6c8](https://github.com/fable-compiler/Fable/commit/bdf0a6c8cb56151a5431b5e3703f7ee165b26dba))
62
+ * *(js/ts)* Accept decimal integers up to 2^96 ([c9feb339](https://github.com/fable-compiler/Fable/commit/c9feb339fb8a4e98bebf17b3facdc42ecd22d628))
63
+ * *(js/ts)* Align decimal conversion, parsing and G format ([6430cdac](https://github.com/fable-compiler/Fable/commit/6430cdacec34e6327434af649eb0c9427d65608c))
64
+ * *(js/ts)* Add missing Async and Task members, cancel timed-out StartChild, bind Async in task { } (#5097) ([d063630d](https://github.com/fable-compiler/Fable/commit/d063630d58d62db21603d45a6bf54b172378c66e))
65
+ * *(js/ts)* Respect maxDegreeOfParallelism and cancel on failure in Async.Parallel (#5098) ([5de3271d](https://github.com/fable-compiler/Fable/commit/5de3271d8b47f1752c4e74c010e4314cf40bbcbe))
66
+
67
+ <strong><small>[View changes on Github](https://github.com/fable-compiler/Fable/compare/e33c57870454fea189a3eb33519f583a5003f8c3..2098f64a25e96385306ef19ed8c289f3b6c84db9)</small></strong>
68
+
18
69
  ## 2.9.0 - 2026-10-16
19
70
 
20
71
  ### 🚀 Features
package/Date.js CHANGED
@@ -376,7 +376,7 @@ function dateToISOStringWithOffset(dateWithOffset, offset) {
376
376
  return str.substring(0, str.length - 1) + dateOffsetToString(offset);
377
377
  }
378
378
  function dateToStringWithOffset(date, format) {
379
- const d = new Date(date.getTime() + (date.offset ?? 0));
379
+ const d = DateTime(date.getTime() + (date.offset ?? 0), DateTimeKind.Utc);
380
380
  if (typeof format !== "string") {
381
381
  return d.toISOString().replace(/\.\d+/, "").replace(/[A-Z]|\.\d+/g, " ") + dateOffsetToString((date.offset ?? 0));
382
382
  }
package/Decimal.js CHANGED
@@ -1,11 +1,20 @@
1
1
  import Decimal from "./lib/big.js";
2
2
  import { symbol } from "./Numeric.js";
3
- import { FSharpRef } from "./Types.js";
4
3
  import { Exception, combineHashCodes } from "./Util.js";
4
+ import { NumberStyles, splitNumber } from "./NumberStyles.js";
5
+ import { ArgumentNullException_$ctor_Z721C83C5, FormatException_$ctor_Z721C83C5, OverflowException_$ctor_Z721C83C5 } from "./System.js";
5
6
  import { fromDecimal } from "./BigInt.js";
6
7
  import * as bigInt from "./BigInt.js";
7
8
  Decimal.prototype.GetHashCode = function () {
8
- return combineHashCodes([this.s, this.e].concat(this.c));
9
+ const digits = this.c;
10
+ if (digits[0] === 0) {
11
+ return combineHashCodes([1, 0, 0]);
12
+ }
13
+ let end = digits.length;
14
+ while (digits[end - 1] === 0) {
15
+ end--;
16
+ }
17
+ return combineHashCodes([this.s, this.e].concat(digits.slice(0, end)));
9
18
  };
10
19
  Decimal.prototype.Equals = function (x) {
11
20
  return !this.cmp(x);
@@ -37,7 +46,7 @@ export function equals(x, y) {
37
46
  }
38
47
  export function abs(x) { return x.abs(); }
39
48
  export function sign(x) { return x.lt(get_Zero) ? -1 : x.gt(get_Zero) ? 1 : 0; }
40
- export function max(x, y) { return x.gt(y) ? x : y; }
49
+ export function max(x, y) { return x.lt(y) ? y : x; }
41
50
  export function min(x, y) { return x.lt(y) ? x : y; }
42
51
  export function maxMagnitude(x, y) { return abs(x).gt(abs(y)) ? x : y; }
43
52
  export function minMagnitude(x, y) { return abs(x).lt(abs(y)) ? x : y; }
@@ -94,23 +103,47 @@ export const negate = op_UnaryNegation;
94
103
  export function toString(x) {
95
104
  return x.toString();
96
105
  }
97
- export function tryParse(str, defValue) {
106
+ // Returns undefined when the string does not have the format allowed by the style
107
+ function parseWithStyle(str, style) {
108
+ const parts = splitNumber(str, style);
109
+ if (parts === undefined) {
110
+ return undefined;
111
+ }
112
+ let d;
113
+ try {
114
+ d = new Decimal(parts.digits);
115
+ }
116
+ catch {
117
+ // Fable's big.js fork throws for values outside the decimal range
118
+ throw OverflowException_$ctor_Z721C83C5(OVERFLOW);
119
+ }
120
+ if (parts.negative) {
121
+ d.s = -1;
122
+ }
123
+ return d;
124
+ }
125
+ export function tryParse(str, style, defValue) {
98
126
  try {
99
- defValue.contents = new Decimal(str.trim());
127
+ const d = parseWithStyle(str, style);
128
+ if (d === undefined) {
129
+ return false;
130
+ }
131
+ defValue.contents = d;
100
132
  return true;
101
133
  }
102
134
  catch {
103
135
  return false;
104
136
  }
105
137
  }
106
- export function parse(str) {
107
- const defValue = new FSharpRef(get_Zero);
108
- if (tryParse(str, defValue)) {
109
- return defValue.contents;
138
+ export function parse(str, style = NumberStyles.Number) {
139
+ if (str == null) {
140
+ throw ArgumentNullException_$ctor_Z721C83C5("s");
110
141
  }
111
- else {
112
- throw new Exception(`The input string ${str} was not in a correct format.`);
142
+ const d = parseWithStyle(str, style);
143
+ if (d === undefined) {
144
+ throw FormatException_$ctor_Z721C83C5(`The input string '${str}' was not in a correct format.`);
113
145
  }
146
+ return d;
114
147
  }
115
148
  export function toNumber(x) {
116
149
  return +x;
@@ -182,6 +215,32 @@ function getInt32Bits(hexDigits, offset) {
182
215
  }
183
216
  return bits;
184
217
  }
218
+ const OVERFLOW = "Value was either too large or too small for a Decimal.";
219
+ // The first double outside the decimal range
220
+ const MAX_DOUBLE = 2 ** 96;
221
+ function fromFloat(n, significantDigits) {
222
+ if (!isFinite(n) || Math.abs(n) >= MAX_DOUBLE) {
223
+ throw new Exception(OVERFLOW);
224
+ }
225
+ const exact = Math.abs(n) >= 1e21 ? BigInt(n).toString() : n.toFixed(100);
226
+ const d = new Decimal(exact).prec(significantDigits, 2);
227
+ const digits = d.c;
228
+ let end = digits.length;
229
+ while (end > 1 && digits[end - 1] === 0) {
230
+ end--;
231
+ }
232
+ d.c = digits.slice(0, end);
233
+ if (d.c[0] === 0) {
234
+ d.e = 0;
235
+ }
236
+ return d;
237
+ }
238
+ export function fromFloat64(n) {
239
+ return fromFloat(n, 15);
240
+ }
241
+ export function fromFloat32(n) {
242
+ return fromFloat(n, 7);
243
+ }
185
244
  export function fromIntArray(bits) {
186
245
  return fromInts(bits[0], bits[1], bits[2], bits[3]);
187
246
  }
package/Double.js CHANGED
@@ -1,25 +1,40 @@
1
1
  import { FSharpRef } from "./Types.js";
2
- import { Exception } from "./Util.js";
3
- export function tryParse(str, defValue) {
4
- // TODO: test if value is valid and in range
5
- if (str != null && /\S/.test(str)) {
6
- const v = +str.replace("_", "");
7
- if (!Number.isNaN(v)) {
8
- defValue.contents = v;
2
+ import { ArgumentNullException_$ctor_Z721C83C5, FormatException_$ctor_Z721C83C5 } from "./System.js";
3
+ import { NumberStyles, splitNumber } from "./NumberStyles.js";
4
+ // .NET's NaN and infinity symbols, ignoring case, allowing a sign and trimmed like String.Trim
5
+ const symbolRegex = /^[\t-\r \u0085\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000]*(?:[+-]?nan|([+-]?)infinity)[\t-\r \u0085\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000]*$/i;
6
+ const defaultStyle = NumberStyles.Float | NumberStyles.AllowThousands;
7
+ export function tryParse(str, style, defValue) {
8
+ if (str != null) {
9
+ const parts = splitNumber(str, style);
10
+ if (parts !== undefined) {
11
+ const value = Number.parseFloat(parts.digits);
12
+ defValue.contents = parts.negative ? -value : value;
13
+ return true;
14
+ }
15
+ const symbol = symbolRegex.exec(str);
16
+ if (symbol != null) {
17
+ defValue.contents = symbol[1] == null ? NaN : symbol[1] === "-" ? -Infinity : Infinity;
9
18
  return true;
10
19
  }
11
20
  }
12
21
  return false;
13
22
  }
14
- export function parse(str) {
23
+ export function parse(str, style = defaultStyle) {
15
24
  const defValue = new FSharpRef(0);
16
- if (tryParse(str, defValue)) {
25
+ if (tryParse(str, style, defValue)) {
17
26
  return defValue.contents;
18
27
  }
28
+ else if (str == null) {
29
+ throw ArgumentNullException_$ctor_Z721C83C5("s");
30
+ }
19
31
  else {
20
- throw new Exception(`The input string ${str} was not in a correct format.`);
32
+ throw FormatException_$ctor_Z721C83C5(`The input string '${str}' was not in a correct format.`);
21
33
  }
22
34
  }
35
+ export function parseIgnoringUnderscores(str) {
36
+ return parse(str == null ? str : str.replace(/_/g, ""), NumberStyles.Float);
37
+ }
23
38
  // JS Number.isFinite function evals false for NaN
24
39
  export function isPositiveInfinity(x) {
25
40
  return x === Number.POSITIVE_INFINITY;
package/FSharp.Core.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { disposeSafe, defaultOf, Exception, structuralHash, equals } from "./Util.js";
2
2
  import { HashIdentity_Structural, ComparisonIdentity_Structural } from "./FSharp.Collections.js";
3
3
  import { nonNullValue } from "./Option.js";
4
- import { NullReferenceException_$ctor, ArgumentNullException_$ctor_Z721C83C5 } from "./System.js";
4
+ import { NullReferenceException_$ctor, InvalidOperationException_$ctor_Z721C83C5, ArgumentException_$ctor_Z384F8060, ArgumentNullException_$ctor_Z721C83C5 } from "./System.js";
5
5
  import { FSharpChoice$2_Choice2Of2, FSharpChoice$2_Choice1Of2 } from "./Choice.js";
6
6
  import { StringBuilder__Append_Z721C83C5 } from "./System.Text.js";
7
7
  export const LanguagePrimitives_GenericEqualityComparer = {
@@ -41,6 +41,12 @@ export function Operators_FailurePattern(exn) {
41
41
  export function Operators_NullArg(argumentName) {
42
42
  throw ArgumentNullException_$ctor_Z721C83C5(argumentName);
43
43
  }
44
+ export function Operators_InvalidArg(argumentName, message) {
45
+ throw ArgumentException_$ctor_Z384F8060(message, argumentName);
46
+ }
47
+ export function Operators_InvalidOp(message) {
48
+ throw InvalidOperationException_$ctor_Z721C83C5(message);
49
+ }
44
50
  export function Operators_Using(resource, action) {
45
51
  try {
46
52
  return action(resource);
package/Global.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export const SR_indexOutOfBounds = "The index was outside the range of elements in the collection.";
2
- export const SR_inputWasEmpty = "Collection was empty.";
2
+ export const SR_inputWasEmpty = "The input list was empty.";
3
3
  export const SR_inputMustBeNonNegative = "The input must be non-negative.";
4
4
  export const SR_inputSequenceEmpty = "The input sequence was empty.";
5
5
  export const SR_inputSequenceTooLong = "The input sequence contains more than one element.";
package/Int32.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Exception } from "./Util.js";
2
+ import { ArgumentNullException_$ctor_Z721C83C5, FormatException_$ctor_Z721C83C5, OverflowException_$ctor_Z721C83C5 } from "./System.js";
2
3
  export const NumberStyles = {
3
4
  // None: 0x00000000,
4
5
  // AllowLeadingWhite: 0x00000001,
@@ -87,7 +88,14 @@ export function isValid(str, style, radix) {
87
88
  }
88
89
  return null;
89
90
  }
91
+ export function parseOverflow(unsigned, bitsize) {
92
+ const type = bitsize === 8 ? (unsigned ? "an unsigned byte" : "a signed byte") : (unsigned ? "a UInt" : "an Int") + bitsize;
93
+ return OverflowException_$ctor_Z721C83C5(`Value was either too large or too small for ${type}.`);
94
+ }
90
95
  export function parse(str, style, unsigned, bitsize, radix) {
96
+ if (str == null) {
97
+ throw ArgumentNullException_$ctor_Z721C83C5("s");
98
+ }
91
99
  const res = isValid(str, style, radix);
92
100
  if (res != null) {
93
101
  let v = Number.parseInt(res.sign + res.digits, res.radix);
@@ -100,9 +108,10 @@ export function parse(str, style, unsigned, bitsize, radix) {
100
108
  if (v >= min && v <= max) {
101
109
  return v;
102
110
  }
111
+ throw parseOverflow(unsigned, bitsize);
103
112
  }
104
113
  }
105
- throw new Exception(`The input string ${str} was not in a correct format.`);
114
+ throw FormatException_$ctor_Z721C83C5(`The input string '${str}' was not in a correct format.`);
106
115
  }
107
116
  export function tryParse(str, style, unsigned, bitsize, defValue) {
108
117
  try {