@fable-org/fable-library-ts 2.0.0-beta.1 → 2.0.0-beta.3

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.ts CHANGED
@@ -159,12 +159,14 @@ export function sleep(millisecondsDueTime: number) {
159
159
  });
160
160
  }
161
161
 
162
- export function runSynchronously(): never {
163
- throw new Error("Asynchronous code cannot be run synchronously in JS");
164
- }
165
-
166
162
  export function start<T>(computation: Async<T>, cancellationToken?: CancellationToken) {
167
- return startWithContinuations(computation, cancellationToken);
163
+ return startWithContinuations(
164
+ computation,
165
+ emptyContinuation,
166
+ function (err) { throw err },
167
+ emptyContinuation,
168
+ cancellationToken
169
+ );
168
170
  }
169
171
 
170
172
  export function startImmediate<T>(computation: Async<T>, cancellationToken?: CancellationToken) {
@@ -173,19 +175,16 @@ export function startImmediate<T>(computation: Async<T>, cancellationToken?: Can
173
175
 
174
176
  export function startWithContinuations<T>(
175
177
  computation: Async<T>,
176
- continuation?: Continuation<T> | CancellationToken,
177
- exceptionContinuation?: Continuation<any>,
178
- cancellationContinuation?: Continuation<any>,
178
+ continuation: Continuation<T>,
179
+ exceptionContinuation: Continuation<any>,
180
+ cancellationContinuation: Continuation<any>,
179
181
  cancelToken?: CancellationToken) {
180
- if (typeof continuation !== "function") {
181
- cancelToken = continuation as CancellationToken;
182
- continuation = undefined;
183
- }
182
+
184
183
  const trampoline = new Trampoline();
185
184
  computation({
186
185
  onSuccess: continuation ? continuation as Continuation<T> : emptyContinuation,
187
- onError: exceptionContinuation ? exceptionContinuation : emptyContinuation,
188
- onCancel: cancellationContinuation ? cancellationContinuation : emptyContinuation,
186
+ onError: exceptionContinuation,
187
+ onCancel: cancellationContinuation,
189
188
  cancelToken: cancelToken ? cancelToken : defaultCancellationToken,
190
189
  trampoline,
191
190
  });
package/BigInt.ts CHANGED
@@ -130,20 +130,46 @@ export function toByteArray(value: bigint): number[] {
130
130
  return toSignedBytes(value, isBigEndian) as any as number[];
131
131
  }
132
132
 
133
- export function toInt8(x: bigint): int8 { return Number(BigInt.asIntN(8, x)); }
134
- export function toUInt8(x: bigint): uint8 { return Number(BigInt.asUintN(8, x)); }
135
- export function toInt16(x: bigint): int16 { return Number(BigInt.asIntN(16, x)); }
136
- export function toUInt16(x: bigint): uint16 { return Number(BigInt.asUintN(16, x)); }
137
- export function toInt32(x: bigint): int32 { return Number(BigInt.asIntN(32, x)); }
138
- export function toUInt32(x: bigint): uint32 { return Number(BigInt.asUintN(32, x)); }
139
- export function toInt64(x: bigint): int64 { return BigInt.asIntN(64, x); }
140
- export function toUInt64(x: bigint): uint64 { return BigInt.asUintN(64, x); }
141
- export function toInt128(x: bigint): int128 { return BigInt.asIntN(128, x); }
142
- export function toUInt128(x: bigint): uint128 { return BigInt.asUintN(128, x); }
143
- export function toNativeInt(x: bigint): nativeint { return BigInt.asIntN(64, x); }
144
- export function toUNativeInt(x: bigint): unativeint { return BigInt.asUintN(64, x); }
145
-
146
- export function toFloat16(x: bigint): float32 { return Number(x); }
133
+ export function toIntN_unchecked(bits: number, x: bigint, signed: boolean): bigint {
134
+ return signed ? BigInt.asIntN(bits, x) : BigInt.asUintN(bits, x);
135
+ }
136
+
137
+ export function toIntN(bits: number, x: bigint, signed: boolean): bigint {
138
+ let higher_bits = abs(x) >> BigInt(bits);
139
+ if (higher_bits !== 0n) {
140
+ const s = signed ? "a signed" : "an unsigned";
141
+ throw new Error(`Value was either too large or too small for ${s} ${bits}-bit integer.`);
142
+ }
143
+ return signed ? BigInt.asIntN(bits, x) : BigInt.asUintN(bits, x);
144
+ }
145
+
146
+ export function toInt8(x: bigint): int8 { return Number(toIntN(8, x, true)); }
147
+ export function toUInt8(x: bigint): uint8 { return Number(toIntN(8, x, false)); }
148
+ export function toInt16(x: bigint): int16 { return Number(toIntN(16, x, true)); }
149
+ export function toUInt16(x: bigint): uint16 { return Number(toIntN(16, x, false)); }
150
+ export function toInt32(x: bigint): int32 { return Number(toIntN(32, x, true)); }
151
+ export function toUInt32(x: bigint): uint32 { return Number(toIntN(32, x, false)); }
152
+ export function toInt64(x: bigint): int64 { return toIntN(64, x, true); }
153
+ export function toUInt64(x: bigint): uint64 { return toIntN(64, x, false); }
154
+ export function toInt128(x: bigint): int128 { return toIntN(128, x, true); }
155
+ export function toUInt128(x: bigint): uint128 { return toIntN(128, x, false); }
156
+ export function toNativeInt(x: bigint): nativeint { return toIntN(64, x, true); }
157
+ export function toUNativeInt(x: bigint): unativeint { return toIntN(64, x, false); }
158
+
159
+ export function toInt8_unchecked(x: bigint): int8 { return Number(toIntN_unchecked(8, x, true)); }
160
+ export function toUInt8_unchecked(x: bigint): uint8 { return Number(toIntN_unchecked(8, x, false)); }
161
+ export function toInt16_unchecked(x: bigint): int16 { return Number(toIntN_unchecked(16, x, true)); }
162
+ export function toUInt16_unchecked(x: bigint): uint16 { return Number(toIntN_unchecked(16, x, false)); }
163
+ export function toInt32_unchecked(x: bigint): int32 { return Number(toIntN_unchecked(32, x, true)); }
164
+ export function toUInt32_unchecked(x: bigint): uint32 { return Number(toIntN_unchecked(32, x, false)); }
165
+ export function toInt64_unchecked(x: bigint): int64 { return toIntN_unchecked(64, x, true); }
166
+ export function toUInt64_unchecked(x: bigint): uint64 { return toIntN_unchecked(64, x, false); }
167
+ export function toInt128_unchecked(x: bigint): int128 { return toIntN_unchecked(128, x, true); }
168
+ export function toUInt128_unchecked(x: bigint): uint128 { return toIntN_unchecked(128, x, false); }
169
+ export function toNativeInt_unchecked(x: bigint): nativeint { return toIntN_unchecked(64, x, true); }
170
+ export function toUNativeInt_unchecked(x: bigint): unativeint { return toIntN_unchecked(64, x, false); }
171
+
172
+ export function toFloat16(x: bigint): float16 { return Number(x); }
147
173
  export function toFloat32(x: bigint): float32 { return Number(x); }
148
174
  export function toFloat64(x: bigint): float64 { return Number(x); }
149
175
 
@@ -191,14 +217,14 @@ export function modPow(x: bigint, e: bigint, m: bigint): bigint {
191
217
  export function divRem(x: bigint, y: bigint): [bigint, bigint];
192
218
  export function divRem(x: bigint, y: bigint, out: FSharpRef<bigint>): bigint;
193
219
  export function divRem(x: bigint, y: bigint, out?: FSharpRef<bigint>): bigint | [bigint, bigint] {
194
- const div = x / y;
195
- const rem = x % y;
196
- if (out === void 0) {
197
- return [div, rem];
198
- } else {
199
- out.contents = rem;
200
- return div;
201
- }
220
+ const div = x / y;
221
+ const rem = x % y;
222
+ if (out === void 0) {
223
+ return [div, rem];
224
+ } else {
225
+ out.contents = rem;
226
+ return div;
227
+ }
202
228
  }
203
229
 
204
230
  export function greatestCommonDivisor(x: bigint, y: bigint): bigint {
package/CHANGELOG.md CHANGED
@@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## Unreleased
9
9
 
10
+ ## 2.0.0-beta.3 - 2025-03-14
11
+
12
+ ### Fixed
13
+
14
+ * [JS/TS] Make `nullArgCheck` report the same error message as on .NET (by @MangelMaxime)
15
+
16
+ ## 2.0.0-beta.2 - 2025-03-03
17
+
18
+ * [JS/TS] Fix #4049: decimal/bigint to integer conversion checks (by @ncave)
19
+ * [JS/TS] Fix `decimal` to `char` conversion checks (by @ManngelMaxime)
20
+ * [JS/TS] Propagate non-captured exception when running `Async.Start` or `Async.StartImmediate` (by @MangelMaxime)
21
+ * [JS/TS] Remove `Async.RunSynchronously` (by @MangelMaxime)
22
+ * [JS/TS] Change signature of `startWithContinuations` to always require all its arguments (by @MangelMaxime)
23
+ * [JS/TS] Fix short `DateTime` and `DateTimeOffset` short format strings (by @MangelMaxime)
24
+ * [JS/TS] Add `C` and `c` format for numeric types (by @MangelMaxime)
25
+ * [JS/TS] Add `B` and `b` format for numeric types (by @MangelMaxime)
26
+ * [JS/TS] Add `n` format for numeric types (by @MangelMaxime)
27
+ * [JS/TS] Fix numeric formats (by @MangelMaxime)
28
+
10
29
  ## 2.0.0-beta.1 - 2025-02-16
11
30
 
12
31
  * Compiled with Fable 5.0.0-alpha.10
@@ -59,7 +78,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
59
78
 
60
79
  * [JS/TS] Fix escaping of `{` and `}` in FormattableString (#3890) (by @roboz0r)
61
80
  * [JS/TS] Fix `uri.Host` to return the host name without the port (by @MangelMaxime)
62
- * [JS/TS] Fix TypeScript compilation by resolving type of `jsOptions` (#3894) (by @ManngelMaxime)
81
+ * [JS/TS] Fix TypeScript compilation by resolving type of `jsOptions` (#3894) (by @MangelMaxime)
63
82
 
64
83
  ## 1.4.3 - 2024-09-04
65
84
 
package/Date.ts CHANGED
@@ -55,7 +55,7 @@ function parseNextChar(format: string, pos: number) {
55
55
  return format.charCodeAt(pos + 1);
56
56
  }
57
57
 
58
- function parseQuotedString(format: string, pos: number) : [string, number] {
58
+ function parseQuotedString(format: string, pos: number): [string, number] {
59
59
  let beginPos = pos;
60
60
  // Get the character used to quote the string
61
61
  const quoteChar = format[pos];
@@ -114,9 +114,8 @@ function dateToStringWithCustomFormat(date: Date, format: string, utc: boolean)
114
114
  result += shortDays[dayOfWeek(localizedDate)];
115
115
  break;
116
116
  case 4:
117
- result += longDays[dayOfWeek(localizedDate)];
118
- break;
119
117
  default:
118
+ result += longDays[dayOfWeek(localizedDate)];
120
119
  break;
121
120
  }
122
121
  break;
@@ -132,7 +131,9 @@ function dateToStringWithCustomFormat(date: Date, format: string, utc: boolean)
132
131
  // milliseconds provided to it.
133
132
  // This is to have the same behavior as .NET when doing:
134
133
  // DateTime(1, 2, 3, 4, 5, 6, DateTimeKind.Utc).ToString("fffff") => 00000
135
- result += (""+millisecond(localizedDate)).padEnd(tokenLength, "0");
134
+ result += ("" + millisecond(localizedDate)).padEnd(tokenLength, "0");
135
+ } else {
136
+ throw "Input string was not in a correct format.";
136
137
  }
137
138
  break;
138
139
  case "F":
@@ -152,14 +153,14 @@ function dateToStringWithCustomFormat(date: Date, format: string, utc: boolean)
152
153
  if (value != 0) {
153
154
  result += padWithZeros(value, 3);
154
155
  }
156
+ } else {
157
+ throw "Input string was not in a correct format.";
155
158
  }
156
159
  break;
157
160
  case "g":
158
161
  tokenLength = parseRepeatToken(format, cursorPos, "g");
159
162
  cursorPos += tokenLength;
160
- if (tokenLength <= 2) {
161
- result += "A.D.";
162
- }
163
+ result += "A.D.";
163
164
  break;
164
165
  case "h":
165
166
  tokenLength = parseRepeatToken(format, cursorPos, "h");
@@ -170,11 +171,10 @@ function dateToStringWithCustomFormat(date: Date, format: string, utc: boolean)
170
171
  result += h1Value ? h1Value : 12;
171
172
  break;
172
173
  case 2:
174
+ default:
173
175
  const h2Value = hour(localizedDate) % 12;
174
176
  result += padWithZeros(h2Value ? h2Value : 12, 2);
175
177
  break;
176
- default:
177
- break;
178
178
  }
179
179
  break;
180
180
  case "H":
@@ -185,9 +185,8 @@ function dateToStringWithCustomFormat(date: Date, format: string, utc: boolean)
185
185
  result += hour(localizedDate);
186
186
  break;
187
187
  case 2:
188
- result += padWithZeros(hour(localizedDate), 2);
189
- break;
190
188
  default:
189
+ result += padWithZeros(hour(localizedDate), 2);
191
190
  break;
192
191
  }
193
192
  break;
@@ -219,9 +218,8 @@ function dateToStringWithCustomFormat(date: Date, format: string, utc: boolean)
219
218
  result += minute(localizedDate);
220
219
  break;
221
220
  case 2:
222
- result += padWithZeros(minute(localizedDate), 2);
223
- break;
224
221
  default:
222
+ result += padWithZeros(minute(localizedDate), 2);
225
223
  break;
226
224
  }
227
225
  break;
@@ -239,9 +237,8 @@ function dateToStringWithCustomFormat(date: Date, format: string, utc: boolean)
239
237
  result += shortMonths[month(localizedDate) - 1];
240
238
  break;
241
239
  case 4:
242
- result += longMonths[month(localizedDate) - 1];
243
- break;
244
240
  default:
241
+ result += longMonths[month(localizedDate) - 1];
245
242
  break;
246
243
  }
247
244
  break;
@@ -253,9 +250,8 @@ function dateToStringWithCustomFormat(date: Date, format: string, utc: boolean)
253
250
  result += second(localizedDate);
254
251
  break;
255
252
  case 2:
256
- result += padWithZeros(second(localizedDate), 2);
257
- break;
258
253
  default:
254
+ result += padWithZeros(second(localizedDate), 2);
259
255
  break;
260
256
  }
261
257
  break;
@@ -267,9 +263,8 @@ function dateToStringWithCustomFormat(date: Date, format: string, utc: boolean)
267
263
  result += localizedDate.getHours() < 12 ? "A" : "P";
268
264
  break;
269
265
  case 2:
270
- result += localizedDate.getHours() < 12 ? "AM" : "PM";
271
- break;
272
266
  default:
267
+ result += localizedDate.getHours() < 12 ? "AM" : "PM";
273
268
  break;
274
269
  }
275
270
  break;
@@ -283,16 +278,8 @@ function dateToStringWithCustomFormat(date: Date, format: string, utc: boolean)
283
278
  case 2:
284
279
  result += padWithZeros(localizedDate.getFullYear() % 100, 2);
285
280
  break;
286
- case 3:
287
- result += padWithZeros(localizedDate.getFullYear(), 3);
288
- break;
289
- case 4:
290
- result += padWithZeros(localizedDate.getFullYear(), 4);
291
- break;
292
- case 5:
293
- result += padWithZeros(localizedDate.getFullYear(), 5);
294
- break;
295
281
  default:
282
+ result += padWithZeros(localizedDate.getFullYear(), tokenLength);
296
283
  break;
297
284
  }
298
285
  break;
@@ -393,13 +380,6 @@ export function dateOffsetToString(offset: number) {
393
380
  padWithZeros(minutes, 2);
394
381
  }
395
382
 
396
- export function dateToHalfUTCString(date: IDateTime, half: "first" | "second") {
397
- const str = date.toISOString();
398
- return half === "first"
399
- ? str.substring(0, str.indexOf("T"))
400
- : str.substring(str.indexOf("T") + 1, str.length - 1);
401
- }
402
-
403
383
  function dateToISOString(d: IDateTime, utc: boolean) {
404
384
  if (utc) {
405
385
  return d.toISOString();
@@ -428,8 +408,10 @@ function dateToStringWithOffset(date: IDateTimeOffset, format?: string) {
428
408
  return d.toISOString().replace(/\.\d+/, "").replace(/[A-Z]|\.\d+/g, " ") + dateOffsetToString((date.offset ?? 0));
429
409
  } else if (format.length === 1) {
430
410
  switch (format) {
431
- case "D": case "d": return dateToHalfUTCString(d, "first");
432
- case "T": case "t": return dateToHalfUTCString(d, "second");
411
+ case "D": return dateToString_D(d);
412
+ case "d": return dateToString_d(d);
413
+ case "T": return dateToString_T(toUniversalTime(d));
414
+ case "t": return dateToString_t(toUniversalTime(d));
433
415
  case "O": case "o": return dateToISOStringWithOffset(d, (date.offset ?? 0));
434
416
  default: throw new Error("Unrecognized Date print format");
435
417
  }
@@ -438,16 +420,40 @@ function dateToStringWithOffset(date: IDateTimeOffset, format?: string) {
438
420
  }
439
421
  }
440
422
 
423
+ function dateToString_D(date: IDateTime) {
424
+ return longDays[dayOfWeek(date)]
425
+ + ", " + padWithZeros(day(date), 2)
426
+ + " " + longMonths[month(date) - 1]
427
+ + " " + year(date);
428
+ }
429
+
430
+ function dateToString_d(date: IDateTime) {
431
+ return padWithZeros(month(date), 2)
432
+ + "/" + padWithZeros(day(date), 2)
433
+ + "/" + year(date);
434
+ }
435
+
436
+ function dateToString_T(date: IDateTime) {
437
+ return padWithZeros(hour(date), 2)
438
+ + ":" + padWithZeros(minute(date), 2)
439
+ + ":" + padWithZeros(second(date), 2);
440
+ }
441
+
442
+ function dateToString_t(date: IDateTime) {
443
+ return padWithZeros(hour(date), 2)
444
+ + ":" + padWithZeros(minute(date), 2);
445
+ }
446
+
441
447
  function dateToStringWithKind(date: IDateTime, format?: string) {
442
448
  const utc = date.kind === DateKind.UTC;
443
449
  if (typeof format !== "string") {
444
450
  return utc ? date.toUTCString() : date.toLocaleString();
445
451
  } else if (format.length === 1) {
446
452
  switch (format) {
447
- case "D": case "d":
448
- return utc ? dateToHalfUTCString(date, "first") : date.toLocaleDateString();
449
- case "T": case "t":
450
- return utc ? dateToHalfUTCString(date, "second") : date.toLocaleTimeString();
453
+ case "D": return dateToString_D(date);
454
+ case "d": return dateToString_d(date);
455
+ case "T": return dateToString_T(date);
456
+ case "t": return dateToString_t(date);
451
457
  case "O": case "o":
452
458
  return dateToISOString(date, utc);
453
459
  default:
package/Decimal.ts CHANGED
@@ -2,6 +2,9 @@ import Decimal, { BigSource } from "./lib/big.js";
2
2
  import { Numeric, symbol } from "./Numeric.js";
3
3
  import { FSharpRef } from "./Types.js";
4
4
  import { combineHashCodes } from "./Util.js";
5
+ import { int8, uint8, int16, uint16, int32, uint32, float16, float32, float64 } from "./Int32.js";
6
+ import { fromDecimal, int64, uint64, int128, uint128, nativeint, unativeint } from "./BigInt.js";
7
+ import * as bigInt from "./BigInt.js";
5
8
 
6
9
  Decimal.prototype.GetHashCode = function () {
7
10
  return combineHashCodes([this.s, this.e].concat(this.c))
@@ -139,10 +142,35 @@ export function parse(str: string): Decimal {
139
142
  }
140
143
  }
141
144
 
142
- export function toNumber(x: Decimal) {
145
+ export function toNumber(x: Decimal): number {
143
146
  return +x;
144
147
  }
145
148
 
149
+ export function toChar(x: Decimal): string {
150
+ const n = toNumber(x);
151
+ if (n < 0 || n > 65535 || isNaN(n)) {
152
+ throw new Error("Value was either too large or too small for a character.");
153
+ }
154
+ return String.fromCharCode(n);
155
+ }
156
+
157
+ export function toInt8(x: Decimal): int8 { return bigInt.toInt8(fromDecimal(x)); }
158
+ export function toUInt8(x: Decimal): uint8 { return bigInt.toUInt8(fromDecimal(x)); }
159
+ export function toInt16(x: Decimal): int16 { return bigInt.toInt16(fromDecimal(x)); }
160
+ export function toUInt16(x: Decimal): uint16 { return bigInt.toUInt16(fromDecimal(x)); }
161
+ export function toInt32(x: Decimal): int32 { return bigInt.toInt32(fromDecimal(x)); }
162
+ export function toUInt32(x: Decimal): uint32 { return bigInt.toUInt32(fromDecimal(x)); }
163
+ export function toInt64(x: Decimal): int64 { return bigInt.toInt64(fromDecimal(x)); }
164
+ export function toUInt64(x: Decimal): uint64 { return bigInt.toUInt64(fromDecimal(x)); }
165
+ export function toInt128(x: Decimal): int128 { return bigInt.toInt128(fromDecimal(x)); }
166
+ export function toUInt128(x: Decimal): uint128 { return bigInt.toUInt128(fromDecimal(x)); }
167
+ export function toNativeInt(x: Decimal): nativeint { return bigInt.toNativeInt(fromDecimal(x)); }
168
+ export function toUNativeInt(x: Decimal): unativeint { return bigInt.toUNativeInt(fromDecimal(x)); }
169
+
170
+ export function toFloat16(x: Decimal): float16 { return toNumber(x); }
171
+ export function toFloat32(x: Decimal): float32 { return toNumber(x); }
172
+ export function toFloat64(x: Decimal): float64 { return toNumber(x); }
173
+
146
174
  function decimalToHex(dec: Uint8Array, bitSize: number) {
147
175
  const hex = new Uint8Array(bitSize / 4 | 0);
148
176
  let hexCount = 1;
package/FSharp.Core.ts CHANGED
@@ -3,6 +3,7 @@ import { int32 } from "./Int32.js";
3
3
  import { HashIdentity_Structural, ComparisonIdentity_Structural } from "./FSharp.Collections.js";
4
4
  import { value as value_1, Nullable, Option } from "./Option.js";
5
5
  import { FSharpChoice$2_$union, FSharpChoice$2_Choice2Of2, FSharpChoice$2_Choice1Of2 } from "./Choice.js";
6
+ import { concat } from "./String.js";
6
7
  import { StringBuilder, StringBuilder__Append_Z721C83C5 } from "./System.Text.js";
7
8
 
8
9
  export const LanguagePrimitives_GenericEqualityComparer: any = {
@@ -159,7 +160,7 @@ export function Operators_NullV<T extends any>(): Nullable<T> {
159
160
 
160
161
  export function Operators_NullArgCheck<T>(argumentName: string, value: T): T {
161
162
  if (equals(value, defaultOf())) {
162
- throw new Error(argumentName);
163
+ throw new Error(concat("Value cannot be null. (Parameter \'", argumentName, ..."\')"));
163
164
  }
164
165
  else {
165
166
  return value;
package/List.ts CHANGED
@@ -450,13 +450,13 @@ export function foldBack2<T1, T2, State>(folder: ((arg0: T1, arg1: T2, arg2: Sta
450
450
  return foldBack2_1<T1, T2, State>(folder, toArray<T1>(xs), toArray<T2>(ys), state);
451
451
  }
452
452
 
453
- export function unfold<State, T>(gen: ((arg0: State) => Option<[T, State]>), state: State): FSharpList<T> {
453
+ export function unfold<State, T>(generator: ((arg0: State) => Option<[T, State]>), state: State): FSharpList<T> {
454
454
  const loop = (acc_mut: State, node_mut: FSharpList<T>): FSharpList<T> => {
455
455
  loop:
456
456
  while (true) {
457
457
  const acc: State = acc_mut, node: FSharpList<T> = node_mut;
458
458
  let t: FSharpList<T>;
459
- const matchValue: Option<[T, State]> = gen(acc);
459
+ const matchValue: Option<[T, State]> = generator(acc);
460
460
  if (matchValue != null) {
461
461
  acc_mut = value_1(matchValue)[1];
462
462
  node_mut = ((t = (new FSharpList(value_1(matchValue)[0], undefined)), (node.tail = t, t)));
package/MapUtil.ts CHANGED
@@ -7,6 +7,7 @@ const CaseRules = {
7
7
  SnakeCase: 2,
8
8
  SnakeCaseAllCaps: 3,
9
9
  KebabCase: 4,
10
+ LowerAll: 5,
10
11
  };
11
12
 
12
13
  function dashify(str: string, separator: string) {
@@ -25,6 +26,8 @@ function changeCase(str: string, caseRule: number) {
25
26
  return dashify(str, "_").toUpperCase();
26
27
  case CaseRules.KebabCase:
27
28
  return dashify(str, "-");
29
+ case CaseRules.LowerAll:
30
+ return str.toLowerCase();
28
31
  case CaseRules.None:
29
32
  default:
30
33
  return str;
package/Numeric.ts CHANGED
@@ -18,6 +18,11 @@ export function isNumeric(x: any) {
18
18
  return typeof x === "number" || typeof x === "bigint" || x?.[symbol];
19
19
  }
20
20
 
21
+ export function isIntegral(x: Numeric) {
22
+ // Not perfect, because in JS we can't distinguish between 1.0 and 1
23
+ return typeof x === "number" && Number.isInteger(x) || typeof x === "bigint";
24
+ }
25
+
21
26
  export function compare(x: Numeric, y: number) {
22
27
  if (typeof x === "number") {
23
28
  return x < y ? -1 : (x > y ? 1 : 0);
@@ -42,7 +47,7 @@ export function toFixed(x: Numeric, dp?: number) {
42
47
  if (typeof x === "number") {
43
48
  return x.toFixed(dp);
44
49
  } else if (typeof x === "bigint") {
45
- return x;
50
+ return x.toString();
46
51
  } else {
47
52
  return x[symbol]().toFixed(dp);
48
53
  }
@@ -52,7 +57,7 @@ export function toPrecision(x: Numeric, sd?: number) {
52
57
  if (typeof x === "number") {
53
58
  return x.toPrecision(sd);
54
59
  } else if (typeof x === "bigint") {
55
- return x;
60
+ return x.toString();
56
61
  } else {
57
62
  return x[symbol]().toPrecision(sd);
58
63
  }
@@ -77,4 +82,4 @@ export function toHex(x: Numeric) {
77
82
  } else {
78
83
  return x[symbol]().toHex();
79
84
  }
80
- }
85
+ }
package/Random.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { uint8, int32, float64 } from "./Int32.js";
2
2
  import { class_type, TypeInfo } from "./Reflection.js";
3
- import { fromFloat64, op_Addition, toInt32, toFloat64, compare, int64, fromInt32, toInt64 } from "./BigInt.js";
3
+ import { fromFloat64, op_Addition, toInt32_unchecked, toFloat64, compare, int64, fromInt32, toInt64_unchecked } from "./BigInt.js";
4
4
  import { Operators_IsNull } from "./FSharp.Core.js";
5
5
  import { item, fill, setItem } from "./Array.js";
6
6
 
@@ -121,8 +121,8 @@ export class Seeded implements IRandom {
121
121
  if (minValue > maxValue) {
122
122
  throw new Error("minValue must be less than maxValue");
123
123
  }
124
- const range: int64 = toInt64(fromInt32(maxValue - minValue));
125
- return ((compare(range, toInt64(fromInt32(2147483647))) <= 0) ? (~~(Seeded__Sample(this$) * toFloat64(range)) + minValue) : ~~toInt32(toInt64(op_Addition(toInt64(fromFloat64(Seeded__GetSampleForLargeRange(this$) * toFloat64(range))), toInt64(fromInt32(minValue)))))) | 0;
124
+ const range: int64 = toInt64_unchecked(fromInt32(maxValue - minValue));
125
+ return ((compare(range, toInt64_unchecked(fromInt32(2147483647))) <= 0) ? (~~(Seeded__Sample(this$) * toFloat64(range)) + minValue) : ~~toInt32_unchecked(toInt64_unchecked(op_Addition(toInt64_unchecked(fromFloat64(Seeded__GetSampleForLargeRange(this$) * toFloat64(range))), toInt64_unchecked(fromInt32(minValue)))))) | 0;
126
126
  }
127
127
  NextDouble(): float64 {
128
128
  const this$: Seeded = this;
package/Range.ts CHANGED
@@ -2,7 +2,7 @@ import { compare } from "./Util.js";
2
2
  import { float64, int32 } from "./Int32.js";
3
3
  import { Option } from "./Option.js";
4
4
  import { unfold, delay } from "./Seq.js";
5
- import { uint64, toUInt64, int64, toInt64, op_Addition, fromZero } from "./BigInt.js";
5
+ import { uint64, toUInt64_unchecked, int64, toInt64_unchecked, op_Addition, fromZero } from "./BigInt.js";
6
6
  import { decimal, op_Addition as op_Addition_1, fromParts } from "./Decimal.js";
7
7
 
8
8
  export function makeRangeStepFunction<T>(step: T, stop: T, zero: T, add: ((arg0: T, arg1: T) => T)): ((arg0: T) => Option<[T, T]>) {
@@ -35,18 +35,18 @@ export function rangeDouble(start: float64, step: float64, stop: float64): Itera
35
35
  }
36
36
 
37
37
  export function rangeInt64(start: int64, step: int64, stop: int64): Iterable<int64> {
38
- return integralRangeStep<int64>(start, step, stop, 0n, (x: int64, y: int64): int64 => toInt64(op_Addition(x, y)));
38
+ return integralRangeStep<int64>(start, step, stop, 0n, (x: int64, y: int64): int64 => toInt64_unchecked(op_Addition(x, y)));
39
39
  }
40
40
 
41
41
  export function rangeUInt64(start: uint64, step: uint64, stop: uint64): Iterable<uint64> {
42
- return integralRangeStep<uint64>(start, step, stop, 0n, (x: uint64, y: uint64): uint64 => toUInt64(op_Addition(x, y)));
42
+ return integralRangeStep<uint64>(start, step, stop, 0n, (x: uint64, y: uint64): uint64 => toUInt64_unchecked(op_Addition(x, y)));
43
43
  }
44
44
 
45
45
  export function rangeChar(start: string, stop: string): Iterable<string> {
46
46
  const intStop: int32 = ~~stop.charCodeAt(0) | 0;
47
- return delay<string>((): Iterable<string> => unfold<int32, string>((c: int32): Option<[string, int32]> => {
48
- if (c <= intStop) {
49
- return [String.fromCharCode(c), c + 1] as [string, int32];
47
+ return delay<string>((): Iterable<string> => unfold<int32, string>((i: int32): Option<[string, int32]> => {
48
+ if (i <= intStop) {
49
+ return [String.fromCharCode(i & 0xFFFF), i + 1] as [string, int32];
50
50
  }
51
51
  else {
52
52
  return undefined;
package/Result.ts CHANGED
@@ -18,7 +18,7 @@ export function FSharpResult$2_Ok<T, TError>(ResultValue: T) {
18
18
  return new FSharpResult$2<T, TError, 0>(0, [ResultValue]);
19
19
  }
20
20
 
21
- export function FSharpResult$2_Error<T, TError>(ErrorValue: TError) {
21
+ export function FSharpResult$2_Error$<T, TError>(ErrorValue: TError) {
22
22
  return new FSharpResult$2<T, TError, 1>(1, [ErrorValue]);
23
23
  }
24
24
 
@@ -40,7 +40,7 @@ export function Result_Map<a, b, c>(mapping: ((arg0: a) => b), result: FSharpRes
40
40
  return FSharpResult$2_Ok<b, c>(mapping(result.fields[0] as any));
41
41
  }
42
42
  else {
43
- return FSharpResult$2_Error<b, c>(result.fields[0] as any);
43
+ return FSharpResult$2_Error$<b, c>(result.fields[0] as any);
44
44
  }
45
45
  }
46
46
 
@@ -49,7 +49,7 @@ export function Result_MapError<a, b, c>(mapping: ((arg0: a) => b), result: FSha
49
49
  return FSharpResult$2_Ok<c, b>(result.fields[0] as any);
50
50
  }
51
51
  else {
52
- return FSharpResult$2_Error<c, b>(mapping(result.fields[0] as any));
52
+ return FSharpResult$2_Error$<c, b>(mapping(result.fields[0] as any));
53
53
  }
54
54
  }
55
55
 
@@ -58,7 +58,7 @@ export function Result_Bind<a, b, c>(binder: ((arg0: a) => FSharpResult$2_$union
58
58
  return binder(result.fields[0] as any);
59
59
  }
60
60
  else {
61
- return FSharpResult$2_Error<b, c>(result.fields[0] as any);
61
+ return FSharpResult$2_Error$<b, c>(result.fields[0] as any);
62
62
  }
63
63
  }
64
64
 
package/String.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { toString as dateToString } from "./Date.js";
2
- import { compare as numericCompare, isNumeric, multiply, Numeric, toExponential, toFixed, toHex, toPrecision } from "./Numeric.js";
2
+ import { compare as numericCompare, isNumeric, isIntegral, multiply, Numeric, toExponential, toFixed, toHex, toPrecision } from "./Numeric.js";
3
3
  import { escape } from "./RegExp.js";
4
4
  import { toString } from "./Types.js";
5
5
 
@@ -295,6 +295,19 @@ export function fsFormat(str: string) {
295
295
  };
296
296
  }
297
297
 
298
+ function splitIntAndDecimalPart(value: string) {
299
+ let [repInt, repDecimal] = value.split(".");
300
+ repDecimal === undefined && (repDecimal = "");
301
+ return {
302
+ integral: repInt,
303
+ decimal: repDecimal
304
+ }
305
+ }
306
+
307
+ function thousandSeparate(value: string) {
308
+ return value.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
309
+ }
310
+
298
311
  export function format(str: string | object, ...args: any[]) {
299
312
  let str2: string;
300
313
  if (typeof str === "object") {
@@ -310,31 +323,89 @@ export function format(str: string | object, ...args: any[]) {
310
323
  throw new Error("Index must be greater or equal to zero and less than the arguments' length.")
311
324
  }
312
325
  let rep = args[idx];
326
+ let parts;
313
327
  if (isNumeric(rep)) {
314
- precision = precision == null ? null : parseInt(precision, 10);
328
+ precision = precision == "" ? null : parseInt(precision, 10);
315
329
  switch (format) {
330
+ case "b": case "B":
331
+ if (!isIntegral(rep)) {
332
+ throw new Error("Format specifier was invalid.");
333
+ }
334
+ rep = (rep >>> 0).toString(2).replace(/^0+/, "").padStart(precision || 1, "0");
335
+ break;
336
+ case "c": case "C":
337
+ const isNegative = isLessThan(rep, 0);
338
+ if (isLessThan(rep, 0)) {
339
+ rep = multiply(rep, -1);
340
+ }
341
+ precision = precision == null ? 2 : precision;
342
+ rep = toFixed(rep, precision);
343
+ parts = splitIntAndDecimalPart(rep);
344
+ rep = "¤" + thousandSeparate(parts.integral) + "." + padRight(parts.decimal, precision, "0");
345
+ if (isNegative) {
346
+ rep = "(" + rep + ")";
347
+ }
348
+ break;
349
+ case "d": case "D":
350
+ if (!isIntegral(rep)) {
351
+ throw new Error("Format specifier was invalid.");
352
+ }
353
+ rep = String(rep);
354
+ if (precision != null) {
355
+ if (rep.startsWith("-")) {
356
+ rep = "-" + padLeft(rep.substring(1), precision, "0");
357
+ } else {
358
+ rep = padLeft(rep, precision, "0");
359
+ }
360
+ }
361
+ break;
362
+ case "e": case "E":
363
+ rep = precision != null ? toExponential(rep, precision) : toExponential(rep);
364
+ break;
316
365
  case "f": case "F":
317
366
  precision = precision != null ? precision : 2;
318
367
  rep = toFixed(rep, precision);
368
+ if (precision > 0) {
369
+ parts = splitIntAndDecimalPart(rep);
370
+ rep = parts.integral + "." + padRight(parts.decimal, precision, "0");
371
+ }
319
372
  break;
320
373
  case "g": case "G":
321
374
  rep = precision != null ? toPrecision(rep, precision) : toPrecision(rep);
375
+ // TODO: Check why some numbers are formatted with decimal part
376
+ rep = trimEnd(trimEnd(rep, "0"), ".");
322
377
  break;
323
- case "e": case "E":
324
- rep = precision != null ? toExponential(rep, precision) : toExponential(rep);
378
+ case "n": case "N":
379
+ precision = precision != null ? precision : 2;
380
+ rep = toFixed(rep, precision);
381
+ parts = splitIntAndDecimalPart(rep);
382
+ rep = thousandSeparate(parts.integral) + "." + padRight(parts.decimal, precision, "0");
325
383
  break;
326
384
  case "p": case "P":
327
385
  precision = precision != null ? precision : 2;
328
- rep = toFixed(multiply(rep, 100), precision) + " %";
329
- break;
330
- case "d": case "D":
331
- rep = precision != null ? padLeft(String(rep), precision, "0") : String(rep);
386
+ rep = toFixed(multiply(rep, 100), precision)
387
+ parts = splitIntAndDecimalPart(rep);
388
+ rep = thousandSeparate(parts.integral) + "." + padRight(parts.decimal, precision, "0") + " %";
332
389
  break;
390
+ case "r": case "R":
391
+ throw new Error("The round-trip format is not supported by Fable");
333
392
  case "x": case "X":
334
- rep = precision != null ? padLeft(toHex(rep), precision, "0") : toHex(rep);
335
- if (format === "X") { rep = rep.toUpperCase(); }
393
+ if (!isIntegral(rep)) {
394
+ throw new Error("Format specifier was invalid.");
395
+ }
396
+ precision = precision != null ? precision : 2;
397
+ rep = padLeft(toHex(rep), precision, "0");
398
+ if (format === "X") {
399
+ rep = rep.toUpperCase();
400
+ }
336
401
  break;
337
402
  default:
403
+ // If we have format and were not able to handle it throw
404
+ // See: https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings#standard-format-specifiers
405
+ if (format) {
406
+ throw new Error("Format specifier was invalid.");
407
+ }
408
+
338
409
  if (pattern) {
339
410
  let sign = "";
340
411
  rep = (pattern as string).replace(/([0#,]+)(\.[0#]+)?/, (_, intPart: string, decimalPart: string) => {
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "private": false,
4
4
  "type": "module",
5
5
  "name": "@fable-org/fable-library-ts",
6
- "version": "2.0.0-beta.1",
6
+ "version": "2.0.0-beta.3",
7
7
  "description": "Core library used by F# projects compiled with fable.io",
8
8
  "author": "Fable Contributors",
9
9
  "license": "MIT",