diff --git a/src/Fable.Cli/CHANGELOG.md b/src/Fable.Cli/CHANGELOG.md index 4045e8036a..76491ea2c1 100644 --- a/src/Fable.Cli/CHANGELOG.md +++ b/src/Fable.Cli/CHANGELOG.md @@ -27,6 +27,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * `Result.ToList` * `Result.ToOption` +#### JavaScript + +* [GH-3745](https://github.com/fable-compiler/Fable/pull/3745) Add support for `ListCollector` (by @nojaf) + * `instance.Add` + * `instance.AddMany` + * `instance.AddManyAndClose` + * `instance.Close` + ### Removed #### JavaScript diff --git a/src/Fable.Transforms/Replacements.Util.fs b/src/Fable.Transforms/Replacements.Util.fs index 610872fab8..94e98ab7a9 100644 --- a/src/Fable.Transforms/Replacements.Util.fs +++ b/src/Fable.Transforms/Replacements.Util.fs @@ -322,7 +322,6 @@ let (|BuiltinDefinition|_|) = | Types.dateOnly -> Some BclDateOnly | Types.timeOnly -> Some BclTimeOnly | "System.Timers.Timer" -> Some BclTimer - | Types.decimal | Types.fsharpSet -> Some(FSharpSet(Any)) | Types.fsharpMap -> Some(FSharpMap(Any, Any)) | Types.hashset -> Some(BclHashSet(Any)) diff --git a/src/Fable.Transforms/Replacements.fs b/src/Fable.Transforms/Replacements.fs index a6af1edad7..dfe79f9db1 100644 --- a/src/Fable.Transforms/Replacements.fs +++ b/src/Fable.Transforms/Replacements.fs @@ -1148,6 +1148,8 @@ let tryEntityIdent (com: Compiler) entFullName = makeImportLib com Any "AsyncReplyChannel" "AsyncBuilder" |> Some | "Microsoft.FSharp.Control.FSharpEvent`1" -> makeImportLib com Any "Event" "Event" |> Some | "Microsoft.FSharp.Control.FSharpEvent`2" -> makeImportLib com Any "Event$2" "Event" |> Some + | "Microsoft.FSharp.Core.CompilerServices.ListCollector`1" -> + makeImportLib com Any "ListCollector$1" "FSharp.Core.CompilerServices" |> Some | _ -> None let tryConstructor com (ent: Entity) = @@ -4566,6 +4568,7 @@ let private replacedModules = "Microsoft.FSharp.Collections.ListModule", listModule "Microsoft.FSharp.Collections.HashIdentity", fsharpModule "Microsoft.FSharp.Collections.ComparisonIdentity", fsharpModule + "Microsoft.FSharp.Core.CompilerServices.ListCollector`1", bclType "Microsoft.FSharp.Core.CompilerServices.RuntimeHelpers", seqModule "Microsoft.FSharp.Collections.SeqModule", seqModule Types.keyValuePair, keyValuePairs diff --git a/src/fable-library/FSharp.Core.CompilerServices.fs b/src/fable-library/FSharp.Core.CompilerServices.fs new file mode 100644 index 0000000000..9482203c54 --- /dev/null +++ b/src/fable-library/FSharp.Core.CompilerServices.fs @@ -0,0 +1,17 @@ +namespace Microsoft.FSharp.Core.CompilerServices + +[] +type ListCollector<'T>() = + let collector = ResizeArray<'T>() + + member this.Add(value: 'T) = collector.Add(value) + + member this.AddMany(values: seq<'T>) = collector.AddRange(values) + + // In the particular case of closing with a final add of an F# list + // we can simply stitch the list into the end of the resulting list + member this.AddManyAndClose(values: seq<'T>) = + collector.AddRange(values) + Seq.toList collector + + member this.Close() = Seq.toList collector diff --git a/src/fable-library/Fable.Library.fsproj b/src/fable-library/Fable.Library.fsproj index c8ffc86036..764d2b4c3f 100644 --- a/src/fable-library/Fable.Library.fsproj +++ b/src/fable-library/Fable.Library.fsproj @@ -33,6 +33,7 @@ + diff --git a/tests/Js/Main/Fable.Tests.fsproj b/tests/Js/Main/Fable.Tests.fsproj index 2d3733bcf2..983cf5539c 100644 --- a/tests/Js/Main/Fable.Tests.fsproj +++ b/tests/Js/Main/Fable.Tests.fsproj @@ -78,6 +78,7 @@ + diff --git a/tests/Js/Main/ListCollectorTests.fs b/tests/Js/Main/ListCollectorTests.fs new file mode 100644 index 0000000000..f4a9f83da9 --- /dev/null +++ b/tests/Js/Main/ListCollectorTests.fs @@ -0,0 +1,53 @@ +module Fable.Tests.ListCollector + +open Util.Testing +open Microsoft.FSharp.Core.CompilerServices + +let cutOffLast list = + let mutable headList = ListCollector<'a>() + + let rec visit list = + match list with + | [] + | [ _ ] -> () + | head :: tail -> + headList.Add(head) + visit tail + + visit list + headList.Close() + +let tests = + testList "ListCollector" [ + testCase "ListCollector.Add and .Close" <| fun () -> + let result = cutOffLast [ 1; 2; 3 ] + result |> equal [ 1; 2 ] + + testCase "ListCollector.Close works for empty list" <| fun () -> + let mutable l = ListCollector<_>() + let result = l.Close() + + result |> equal [] + + testCase "ListCollector.AddMany works" <| fun () -> + let mutable l = ListCollector<_>() + l.AddMany([ 1; 2; 3 ]) + + let result = l.Close() + + result |> equal [ 1; 2; 3 ] + + testCase "ListCollector.AddMany works for empty list" <| fun () -> + let mutable l = ListCollector<_>() + l.AddMany([]) + + let result = l.Close() + + result |> equal [] + + testCase "ListCollector.AddManyAndClose works" <| fun () -> + let mutable l = ListCollector<_>() + let result = l.AddManyAndClose([ 1; 2; 3 ]) + + result |> equal [ 1; 2; 3 ] + ] diff --git a/tests/Js/Main/Main.fs b/tests/Js/Main/Main.fs index f145fe5341..17837f9aa3 100644 --- a/tests/Js/Main/Main.fs +++ b/tests/Js/Main/Main.fs @@ -50,6 +50,7 @@ let allTests = TypeTests.tests UnionTypes.tests Uri.tests + ListCollector.tests |] #if FABLE_COMPILER