├── .config └── dotnet-tools.json ├── .gitattributes ├── .github └── workflows │ └── build.yml ├── .gitignore ├── CHANGELOG.md ├── Directory.Build.props ├── FSharpWrap.TestProjects.sln ├── FSharpWrap.sln ├── LICENSE ├── README.md ├── build.fsx ├── build.fsx.lock ├── docs ├── .gitignore ├── _lib │ └── Fornax.Core.dll ├── config.fsx ├── content │ ├── FSharpWrap.Documentation.fsproj │ ├── collection-computation-expressions.fsx │ ├── getting-started.fsx │ ├── index.fsx │ ├── msbuild.fsx │ ├── multi-target.fsx │ └── paket.references ├── generators │ ├── page.fsx │ └── static.fsx ├── js │ ├── codecopy.js │ └── highlight.js ├── loaders │ └── article.fsx └── style │ └── main.css ├── global.json ├── paket.dependencies ├── paket.lock ├── src ├── FSharpWrap.Tool │ ├── FSharpWrap.Tool.fsproj │ ├── Filter.fs │ ├── FsName.fs │ ├── Generation │ │ ├── Generate.fs │ │ ├── ParamList.fs │ │ ├── Print.fs │ │ └── Types.fs │ ├── Namespace.fs │ ├── Options.fs │ ├── Path.fs │ ├── Program.fs │ ├── Reflection │ │ ├── Context.fs │ │ ├── MemberPatterns.fs │ │ ├── Modules.fs │ │ ├── Reflect.fs │ │ ├── TypeArgList.fs │ │ └── Types.fs │ ├── Utils.fs │ └── paket.references └── FSharpWrap │ ├── .gitignore │ ├── FSharpWrap.nuspec │ └── FSharpWrap.targets └── test ├── .gitignore ├── Directory.Build.targets ├── FSharpWrap.Benchmarks ├── Benchmarks.fs ├── FSharpWrap.Benchmarks.fsproj └── paket.references ├── FSharpWrap.Tool.Tests ├── FSharpWrap.Tool.Tests.fsproj ├── Gen.fs ├── GenerateTests.fs ├── OptionsTests.fs └── Test.fs ├── TestProject.CSharpDependency ├── MyCustomList.cs ├── MyString.cs ├── TestProject.CSharpDependency.csproj └── TestProject.CSharpDependency.csproj.paket.references ├── TestProject.CSharpDependent ├── Program.fs └── TestProject.CSharpDependent.fsproj ├── TestProject.Collections ├── Test.fs └── TestProject.Collections.fsproj ├── TestProject.MultiTarget ├── Test.fs └── TestProject.MultiTarget.fsproj ├── TestProject.targets └── paket.references /.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "fake-cli": { 6 | "version": "5.20.3", 7 | "commands": [ 8 | "fake" 9 | ] 10 | }, 11 | "fornax": { 12 | "version": "0.13.1", 13 | "commands": [ 14 | "fornax" 15 | ] 16 | }, 17 | "paket": { 18 | "version": "5.257.0", 19 | "commands": [ 20 | "paket" 21 | ] 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | tags: 7 | - 'v*' 8 | pull_request: 9 | 10 | jobs: 11 | build: 12 | outputs: 13 | release_notes_changes: ${{ steps.release_notes.outputs.changes }} 14 | release_notes_version: ${{ steps.release_notes.outputs.version }} 15 | release_notes_status: ${{ steps.release_notes.outputs.status }} 16 | runs-on: ${{ matrix.os }} 17 | strategy: 18 | matrix: 19 | os: [ ubuntu-latest, windows-latest ] 20 | env: 21 | DOTNET_NOLOGO: true 22 | steps: 23 | - uses: actions/checkout@v2 24 | - name: Setup .NET 5.0 25 | uses: actions/setup-dotnet@v1 26 | with: 27 | dotnet-version: '5.0.x' 28 | - name: Setup .NET 3.1 29 | uses: actions/setup-dotnet@v1 30 | with: 31 | dotnet-version: '3.1.x' 32 | - name: Get Tag Version 33 | id: release_version 34 | if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'ubuntu-latest' 35 | run: | 36 | echo ::set-output name=current_version::${GITHUB_REF#refs/tags/v} 37 | shell: bash 38 | - name: Read Changelog 39 | id: release_notes 40 | if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'ubuntu-latest' 41 | uses: mindsers/changelog-reader-action@v2 42 | with: 43 | version: ${{ steps.release_version.outputs.current_version }} 44 | path: ./CHANGELOG.md 45 | - name: Update Release Notes 46 | if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'ubuntu-latest' 47 | run: | 48 | echo "PACKAGE_VERSION=${{ steps.release_notes.outputs.version }}" >> $GITHUB_ENV 49 | shell: bash 50 | - name: Setup NuGet 51 | uses: nuget/setup-nuget@v1 52 | with: 53 | nuget-version: '5.x' 54 | - name: Install Tools 55 | run: dotnet tool restore 56 | - name: Determine Target 57 | id: build_script_target 58 | run: | 59 | if ("${{ matrix.os }}" -eq "ubuntu-latest") { 60 | $target = "Pack" 61 | } 62 | else { 63 | $target = "Test MSBuild" 64 | } 65 | 66 | -join("::set-output name=target::", $target) | Write-Host 67 | shell: pwsh 68 | - name: Build 69 | run: dotnet fake run build.fsx -t "${{ steps.build_script_target.outputs.target }}" 70 | - name: Upload Packages 71 | if: matrix.os == 'ubuntu-latest' 72 | uses: actions/upload-artifact@v2 73 | with: 74 | name: FSharpWrap 75 | path: | 76 | ./out/*.nupkg 77 | ./out/BenchmarkDotNet.Artifacts/results/*.* 78 | ./docs/_public/** 79 | ./CHANGELOG.md 80 | publish: 81 | if: startsWith(github.ref, 'refs/tags/v') 82 | needs: [build] 83 | runs-on: ubuntu-latest 84 | steps: 85 | - name: Setup NuGet 86 | uses: nuget/setup-nuget@v1 87 | with: 88 | nuget-version: '5.x' 89 | - name: Download Packages 90 | uses: actions/download-artifact@v2 91 | with: 92 | name: FSharpWrap 93 | - name: Publish GitHub 94 | uses: ncipollo/release-action@v1 95 | with: 96 | allowUpdates: true 97 | artifacts: ./out/*.nupkg 98 | body: ${{ needs.build.outputs.release_notes_changes }} 99 | prerelease: ${{ needs.build.outputs.release_notes_status == 'prereleased' }} 100 | token: ${{ secrets.GITHUB_TOKEN }} 101 | - name: Publish NuGet 102 | run: | 103 | nuget push ./out/FSharpWrap.${{ needs.build.outputs.release_notes_version }}.nupkg -ApiKey ${{ secrets.NUGET_API_KEY }} -Source https://api.nuget.org/v3/index.json 104 | documentation: 105 | if: github.ref == 'refs/heads/master' 106 | needs: [build] 107 | runs-on: ubuntu-latest 108 | steps: 109 | - name: Download Packages 110 | uses: actions/download-artifact@v2 111 | with: 112 | name: FSharpWrap 113 | - name: Publish Documentation 114 | uses: JamesIves/github-pages-deploy-action@3.7.1 115 | with: 116 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 117 | BRANCH: gh-pages 118 | FOLDER: docs/_public 119 | CLEAN: true 120 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # JustCode is a .NET coding add-in 131 | .JustCode 132 | 133 | # TeamCity is a build add-in 134 | _TeamCity* 135 | 136 | # DotCover is a Code Coverage Tool 137 | *.dotCover 138 | 139 | # AxoCover is a Code Coverage Tool 140 | .axoCover/* 141 | !.axoCover/settings.json 142 | 143 | # Visual Studio code coverage results 144 | *.coverage 145 | *.coveragexml 146 | 147 | # NCrunch 148 | _NCrunch_* 149 | .*crunch*.local.xml 150 | nCrunchTemp_* 151 | 152 | # MightyMoose 153 | *.mm.* 154 | AutoTest.Net/ 155 | 156 | # Web workbench (sass) 157 | .sass-cache/ 158 | 159 | # Installshield output folder 160 | [Ee]xpress/ 161 | 162 | # DocProject is a documentation generator add-in 163 | DocProject/buildhelp/ 164 | DocProject/Help/*.HxT 165 | DocProject/Help/*.HxC 166 | DocProject/Help/*.hhc 167 | DocProject/Help/*.hhk 168 | DocProject/Help/*.hhp 169 | DocProject/Help/Html2 170 | DocProject/Help/html 171 | 172 | # Click-Once directory 173 | publish/ 174 | 175 | # Publish Web Output 176 | *.[Pp]ublish.xml 177 | *.azurePubxml 178 | # Note: Comment the next line if you want to checkin your web deploy settings, 179 | # but database connection strings (with potential passwords) will be unencrypted 180 | *.pubxml 181 | *.publishproj 182 | 183 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 184 | # checkin your Azure Web App publish settings, but sensitive information contained 185 | # in these scripts will be unencrypted 186 | PublishScripts/ 187 | 188 | # NuGet Packages 189 | *.nupkg 190 | # NuGet Symbol Packages 191 | *.snupkg 192 | # The packages folder can be ignored because of Package Restore 193 | **/[Pp]ackages/* 194 | # except build/, which is used as an MSBuild target. 195 | !**/[Pp]ackages/build/ 196 | # Uncomment if necessary however generally it will be regenerated when needed 197 | #!**/[Pp]ackages/repositories.config 198 | # NuGet v3's project.json files produces more ignorable files 199 | *.nuget.props 200 | *.nuget.targets 201 | 202 | # Microsoft Azure Build Output 203 | csx/ 204 | *.build.csdef 205 | 206 | # Microsoft Azure Emulator 207 | ecf/ 208 | rcf/ 209 | 210 | # Windows Store app package directories and files 211 | AppPackages/ 212 | BundleArtifacts/ 213 | Package.StoreAssociation.xml 214 | _pkginfo.txt 215 | *.appx 216 | *.appxbundle 217 | *.appxupload 218 | 219 | # Visual Studio cache files 220 | # files ending in .cache can be ignored 221 | *.[Cc]ache 222 | # but keep track of directories ending in .cache 223 | !?*.[Cc]ache/ 224 | 225 | # Others 226 | ClientBin/ 227 | ~$* 228 | *~ 229 | *.dbmdl 230 | *.dbproj.schemaview 231 | *.jfm 232 | *.pfx 233 | *.publishsettings 234 | orleans.codegen.cs 235 | 236 | # Including strong name files can present a security risk 237 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 238 | #*.snk 239 | 240 | # Since there are multiple workflows, uncomment next line to ignore bower_components 241 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 242 | #bower_components/ 243 | 244 | # RIA/Silverlight projects 245 | Generated_Code/ 246 | 247 | # Backup & report files from converting an old project file 248 | # to a newer Visual Studio version. Backup files are not needed, 249 | # because we have git ;-) 250 | _UpgradeReport_Files/ 251 | Backup*/ 252 | UpgradeLog*.XML 253 | UpgradeLog*.htm 254 | ServiceFabricBackup/ 255 | *.rptproj.bak 256 | 257 | # SQL Server files 258 | *.mdf 259 | *.ldf 260 | *.ndf 261 | 262 | # Business Intelligence projects 263 | *.rdl.data 264 | *.bim.layout 265 | *.bim_*.settings 266 | *.rptproj.rsuser 267 | *- [Bb]ackup.rdl 268 | *- [Bb]ackup ([0-9]).rdl 269 | *- [Bb]ackup ([0-9][0-9]).rdl 270 | 271 | # Microsoft Fakes 272 | FakesAssemblies/ 273 | 274 | # GhostDoc plugin setting file 275 | *.GhostDoc.xml 276 | 277 | # Node.js Tools for Visual Studio 278 | .ntvs_analysis.dat 279 | node_modules/ 280 | 281 | # Visual Studio 6 build log 282 | *.plg 283 | 284 | # Visual Studio 6 workspace options file 285 | *.opt 286 | 287 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 288 | *.vbw 289 | 290 | # Visual Studio LightSwitch build output 291 | **/*.HTMLClient/GeneratedArtifacts 292 | **/*.DesktopClient/GeneratedArtifacts 293 | **/*.DesktopClient/ModelManifest.xml 294 | **/*.Server/GeneratedArtifacts 295 | **/*.Server/ModelManifest.xml 296 | _Pvt_Extensions 297 | 298 | # Paket dependency manager 299 | .paket/ 300 | paket-files/ 301 | 302 | # FAKE - F# Make 303 | .fake/ 304 | 305 | # CodeRush personal settings 306 | .cr/personal 307 | 308 | # Python Tools for Visual Studio (PTVS) 309 | __pycache__/ 310 | *.pyc 311 | 312 | # Cake - Uncomment if you are using it 313 | # tools/** 314 | # !tools/packages.config 315 | 316 | # Tabs Studio 317 | *.tss 318 | 319 | # Telerik's JustMock configuration file 320 | *.jmconfig 321 | 322 | # BizTalk build output 323 | *.btp.cs 324 | *.btm.cs 325 | *.odx.cs 326 | *.xsd.cs 327 | 328 | # OpenCover UI analysis results 329 | OpenCover/ 330 | 331 | # Azure Stream Analytics local run output 332 | ASALocalRun/ 333 | 334 | # MSBuild Binary and Structured Log 335 | *.binlog 336 | 337 | # NVidia Nsight GPU debugger configuration file 338 | *.nvuser 339 | 340 | # MFractors (Xamarin productivity tool) working folder 341 | .mfractor/ 342 | 343 | # Local History for Visual Studio 344 | .localhistory/ 345 | 346 | # BeatPulse healthcheck temp database 347 | healthchecksdb 348 | 349 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 350 | MigrationBackup/ 351 | 352 | # Ionide (cross platform F# VS Code tools) working folder 353 | .ionide/ 354 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | ## [0.5.0] - 2020-12-08 10 | ### Added 11 | - Generation of computation expressions for types implementing `IEnumerable` 12 | ### Changed 13 | - Generated modules now have `internal` access 14 | - Update documentation to use `.fsx` scripts 15 | 16 | ## [0.4.1] - 2020-11-27 17 | ### Added 18 | - Documentation site available at https://davnavr.github.io/FSharpWrap/ 19 | ### Fixed 20 | - Add check to avoid generating members whose names end with "$W" on computation expression types 21 | - Add leading space in front of string literals used in custom attribute properties to avoid compilation errors 22 | 23 | ## [0.4.0] - 2020-11-24 24 | ### Added 25 | - Small performance improvements 26 | - Additional properties to specify which assemblies and namespaces to include in code generation 27 | - Support for projects with multiple target frameworks 28 | ### Changed 29 | - All assemblies are included in code generation by default 30 | 31 | ## [0.3.0] - 2020-11-13 32 | ### Added 33 | - Filtering of assemblies to avoid generating code for dependencies you won't use 34 | 35 | ## [0.2.0] - 2020-11-08 36 | ### Added 37 | - Copying of `ObsoleteAttribute` and `ExperimentalAttribute` on correponding modules and members 38 | - Suppression of warnings FS0044, FS0057, and FS0064 in generated code 39 | - Generation of functions for read-only instance fields and read-only instance properties 40 | - Code generation target now only runs for F# (`.fsproj`) projects 41 | - Now compatible with `` dependencies 42 | ### Changed 43 | - Exclusion of members marked `ObsoleteAttribute` when `IsError` is `true` to avoid errors that cannot be suppressed 44 | - Exclusion of structs not marked with `IsReadOnlyAttribute` from code generation to avoid problems with non-readonly members 45 | - Exclusion of members containing `byref` parameters from code generation to avoid FS0412 and FS3300 errors 46 | ### Removed 47 | - Code generation for mutable instance fields 48 | 49 | ## [0.1.0] - 2020-09-06 50 | ### Added 51 | - Basic code generation for all dependencies 52 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.7 5 | en-US 6 | $(AssemblyName) 7 | $(MSBuildThisFileDirectory) 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /FSharpWrap.TestProjects.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30711.63 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "TestProject.Collections", "test\TestProject.Collections\TestProject.Collections.fsproj", "{D3215B3F-23C7-41D7-A76D-4F4697651403}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestProject.CSharpDependency", "test\TestProject.CSharpDependency\TestProject.CSharpDependency.csproj", "{4B48616F-ED24-4A61-8741-D0F7967A922D}" 9 | EndProject 10 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "TestProject.CSharpDependent", "test\TestProject.CSharpDependent\TestProject.CSharpDependent.fsproj", "{73213ADA-6F69-4434-BD06-D7CB94007F98}" 11 | EndProject 12 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "TestProject.MultiTarget", "test\TestProject.MultiTarget\TestProject.MultiTarget.fsproj", "{4207CA20-97D4-401E-BE4F-B1C333975573}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {D3215B3F-23C7-41D7-A76D-4F4697651403}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {D3215B3F-23C7-41D7-A76D-4F4697651403}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {D3215B3F-23C7-41D7-A76D-4F4697651403}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {D3215B3F-23C7-41D7-A76D-4F4697651403}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {4B48616F-ED24-4A61-8741-D0F7967A922D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {4B48616F-ED24-4A61-8741-D0F7967A922D}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {4B48616F-ED24-4A61-8741-D0F7967A922D}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {4B48616F-ED24-4A61-8741-D0F7967A922D}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {73213ADA-6F69-4434-BD06-D7CB94007F98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {73213ADA-6F69-4434-BD06-D7CB94007F98}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {73213ADA-6F69-4434-BD06-D7CB94007F98}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {73213ADA-6F69-4434-BD06-D7CB94007F98}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {4207CA20-97D4-401E-BE4F-B1C333975573}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {4207CA20-97D4-401E-BE4F-B1C333975573}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {4207CA20-97D4-401E-BE4F-B1C333975573}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {4207CA20-97D4-401E-BE4F-B1C333975573}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {F36775C3-AE66-40F5-913B-62C4895083AB} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /FSharpWrap.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30413.136 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharpWrap.Tool", "src\FSharpWrap.Tool\FSharpWrap.Tool.fsproj", "{1C1D828E-547F-441E-9727-E288CD4A3A38}" 7 | EndProject 8 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharpWrap.Tool.Tests", "test\FSharpWrap.Tool.Tests\FSharpWrap.Tool.Tests.fsproj", "{B1CB6187-AD83-4814-B230-322A2A9D2956}" 9 | EndProject 10 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharpWrap.Benchmarks", "test\FSharpWrap.Benchmarks\FSharpWrap.Benchmarks.fsproj", "{01EFBF63-67DD-4A4D-B079-C8A8715FB6FF}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {1C1D828E-547F-441E-9727-E288CD4A3A38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {1C1D828E-547F-441E-9727-E288CD4A3A38}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {1C1D828E-547F-441E-9727-E288CD4A3A38}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {1C1D828E-547F-441E-9727-E288CD4A3A38}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {B1CB6187-AD83-4814-B230-322A2A9D2956}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {B1CB6187-AD83-4814-B230-322A2A9D2956}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {B1CB6187-AD83-4814-B230-322A2A9D2956}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {B1CB6187-AD83-4814-B230-322A2A9D2956}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {01EFBF63-67DD-4A4D-B079-C8A8715FB6FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {01EFBF63-67DD-4A4D-B079-C8A8715FB6FF}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {01EFBF63-67DD-4A4D-B079-C8A8715FB6FF}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {01EFBF63-67DD-4A4D-B079-C8A8715FB6FF}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {346EBCE2-B298-407A-B7AB-C3777DF65B69} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FSharpWrap 2 | [![Build Status](https://github.com/davnavr/FSharpWrap/workflows/Build/badge.svg)](https://github.com/davnavr/FSharpWrap/actions?query=workflow%3ABuild) 3 | [![Nuget](https://img.shields.io/nuget/v/FSharpWrap)](https://www.nuget.org/packages/FSharpWrap/) 4 | ![GitHub top language](https://img.shields.io/github/languages/top/davnavr/fsharpwrap) 5 | [![Project Status: WIP – Initial development is in progress, but there has not yet been a stable, usable release suitable for the public.](https://www.repostatus.org/badges/latest/wip.svg)](https://www.repostatus.org/#wip) 6 | 7 | Utility that automatically generates F# modules, functions, and active patterns 8 | based on your F# project file's references. 9 | 10 | ## Usage 11 | For information on how to use and configure FSharpWrap, 12 | [see the docs](https://davnavr.github.io/FSharpWrap/getting-started.html). 13 | 14 | ## Example 15 | A dependency containing the following C# class: 16 | 17 | ```cs 18 | public class ExampleDictionary 19 | { 20 | public void SetItem(TKey key, TValue value); 21 | } 22 | ``` 23 | 24 | Could then be used in the following way: 25 | ```fs 26 | let myDict = new ExampleDictionary() 27 | ExampleDictionary.setItem "hello" 5 myDict 28 | ``` 29 | -------------------------------------------------------------------------------- /build.fsx: -------------------------------------------------------------------------------- 1 | #if FAKE_DEPENDENCIES 2 | #r "paket: 3 | nuget Fake.Core.Target 4 | nuget Fake.DotNet.Cli 5 | nuget Fake.DotNet.NuGet 6 | nuget Fake.IO.FileSystem 7 | //" 8 | #endif 9 | 10 | #load "./.fake/build.fsx/intellisense.fsx" 11 | 12 | open Fake.Core 13 | open Fake.Core.TargetOperators 14 | open Fake.DotNet 15 | open Fake.IO 16 | open Fake.IO.FileSystemOperators 17 | open Fake.IO.Globbing.Operators 18 | 19 | module DotNetCli = Fake.DotNet.DotNet 20 | module NuGetCli = Fake.DotNet.NuGet.NuGet 21 | 22 | let rootDir = __SOURCE_DIRECTORY__ 23 | let docsDir = rootDir "docs" 24 | let outDir = rootDir "out" 25 | let srcDir = rootDir "src" 26 | let mainSln = rootDir "FSharpWrap.sln" 27 | let testSln = rootDir "FSharpWrap.TestProjects.sln" 28 | let toolProj = srcDir "FSharpWrap.Tool" "FSharpWrap.Tool.fsproj" 29 | let docsProj = docsDir "content" "FSharpWrap.Documentation.fsproj" 30 | let testDir = rootDir "test" 31 | 32 | let version = Environment.environVarOrDefault "PACKAGE_VERSION" "0.0.0" 33 | 34 | [] 35 | module Helpers = 36 | let handleErr msg: ProcessResult -> _ = 37 | function 38 | | { ExitCode = ecode } when ecode <> 0 -> 39 | failwithf "Process exited with code %i: %s" ecode msg 40 | | _ -> () 41 | 42 | let buildProj proj props = 43 | DotNetCli.build 44 | (fun opt -> 45 | { opt with 46 | Configuration = DotNetCli.Release 47 | MSBuildParams = { opt.MSBuildParams with Properties = props } 48 | NoRestore = true }) 49 | proj 50 | 51 | let runProj args proj = 52 | [ 53 | "--configuration Release" 54 | "--no-build" 55 | "--no-restore" 56 | ] 57 | |> args 58 | |> String.concat " " 59 | |> sprintf 60 | "--project %s %s" 61 | proj 62 | |> DotNetCli.exec 63 | id 64 | "run" 65 | 66 | Target.create "Restore" <| fun _ -> 67 | DotNetCli.exec 68 | id 69 | "paket" 70 | "restore" 71 | |> handleErr "Error occurred during Paket restore" 72 | 73 | for sln in [ mainSln; testSln; docsProj ] do 74 | DotNetCli.restore id sln 75 | 76 | Target.create "Clean" <| fun _ -> 77 | Shell.cleanDir outDir 78 | Shell.cleanDir (docsDir "_public") 79 | 80 | !!(testDir "**" "*.autogen.fs") |> File.deleteAll 81 | 82 | List.allPairs 83 | [ "Debug"; "Release" ] 84 | [ 85 | mainSln 86 | rootDir "FSharpWrap.TestProjects.sln" 87 | ] 88 | |> List.iter 89 | (fun (cfg, sln) -> 90 | let err = 91 | sprintf "Unexpected error while cleaning solution %s" sln 92 | [ 93 | sln 94 | sprintf "--configuration %s" cfg 95 | ] 96 | |> String.concat " " 97 | |> DotNetCli.exec id "clean" 98 | |> handleErr err) 99 | 100 | Target.create "Build Tool" <| fun _ -> 101 | buildProj mainSln [ "Version", version; "TreatWarningsAsErrors", "true" ] 102 | 103 | DotNetCli.publish 104 | (fun options -> 105 | { options with 106 | Configuration = DotNetCli.Release 107 | NoBuild = true 108 | NoRestore = true 109 | OutputPath = srcDir "FSharpWrap" "tool" |> Some }) 110 | toolProj 111 | 112 | Target.create "Test Tool" <| fun _ -> 113 | testDir "FSharpWrap.Tool.Tests" "FSharpWrap.Tool.Tests.fsproj" 114 | |> runProj id 115 | |> handleErr "One or more tests failed" 116 | 117 | Target.create "Build MSBuild" <| fun _ -> 118 | buildProj 119 | testSln 120 | [ 121 | "_FSharpWrapLaunchDebugger", Environment.environVarOrDefault "DEBUG_FSHARPWRAP_TOOL" "false" 122 | "TreatWarningsAsErrors", "true" 123 | ] 124 | 125 | Target.create "Test MSBuild" <| fun _ -> 126 | let run proj tfms = 127 | let msg = sprintf "Error while running test project %s" proj 128 | List.iter 129 | (fun tfm -> 130 | runProj 131 | (fun args -> sprintf "--framework %s" tfm :: args) 132 | proj 133 | |> handleErr msg) 134 | tfms 135 | [ 136 | "TestProject.Collections" "TestProject.Collections.fsproj", [ "netcoreapp3.1" ] 137 | "TestProject.CSharpDependent" "TestProject.CSharpDependent.fsproj", [ "netcoreapp3.1" ] 138 | "TestProject.MultiTarget" "TestProject.MultiTarget.fsproj", [ "netcoreapp3.1"; "net5.0" ] 139 | ] 140 | |> Map.ofList 141 | |> Map.iter (fun proj -> testDir proj |> run) 142 | 143 | Target.create "Run Benchmarks" <| fun _ -> 144 | testDir "FSharpWrap.Benchmarks" "FSharpWrap.Benchmarks.fsproj" 145 | |> runProj 146 | (fun _ -> 147 | [ 148 | "--configuration Release" 149 | "--framework net5.0" 150 | "--no-restore" 151 | "--" 152 | "--runtimes netcoreapp31 netcoreapp50" 153 | "--filter *" 154 | "--artifacts" 155 | outDir "BenchmarkDotNet.Artifacts" 156 | ]) 157 | |> handleErr "One or more benchmarks could not be run successfully" 158 | 159 | Target.create "Build Documentation" <| fun _ -> 160 | buildProj docsProj [] 161 | Shell.chdir docsDir 162 | DotNetCli.exec id "fornax" "build" |> handleErr "An error occured while building documentation" 163 | Shell.chdir rootDir 164 | 165 | Target.create "Pack" <| fun _ -> 166 | let nuspec = srcDir "FSharpWrap" "FSharpWrap.nuspec" 167 | NuGetCli.NuGetPackDirectly 168 | (fun nparams -> 169 | { nparams with 170 | OutputPath = outDir 171 | Properties = 172 | [ 173 | "Name", "FSharpWrap" 174 | "PackageVersion", version 175 | "PackageReleaseNotes", sprintf "https://github.com/davnavr/FSharpWrap/blob/v%s/CHANGELOG.md" version 176 | "RootDir", rootDir 177 | ] 178 | Version = version 179 | WorkingDir = rootDir }) 180 | nuspec 181 | 182 | "Restore" 183 | ==> "Clean" 184 | ==> "Build Tool" 185 | ==> "Test Tool" 186 | ==> "Build MSBuild" 187 | ==> "Test MSBuild" 188 | ==> "Pack" 189 | 190 | "Test Tool" ==> "Run Benchmarks" ?=> "Build MSBuild" 191 | "Run Benchmarks" ==> "Pack" 192 | 193 | "Build Tool" ==> "Build Documentation" ?=> "Run Benchmarks" 194 | "Build Documentation" ==> "Pack" 195 | 196 | Target.runOrDefault "Test MSBuild" 197 | -------------------------------------------------------------------------------- /build.fsx.lock: -------------------------------------------------------------------------------- 1 | STORAGE: NONE 2 | RESTRICTION: == netstandard2.0 3 | NUGET 4 | remote: https://api.nuget.org/v3/index.json 5 | BlackFox.VsWhere (1.1) 6 | FSharp.Core (>= 4.2.3) 7 | Microsoft.Win32.Registry (>= 4.7) 8 | Fake.Core.CommandLineParsing (5.20.3) 9 | FParsec (>= 1.1.1) 10 | FSharp.Core (>= 4.7.2) 11 | Fake.Core.Context (5.20.3) 12 | FSharp.Core (>= 4.7.2) 13 | Fake.Core.Environment (5.20.3) 14 | FSharp.Core (>= 4.7.2) 15 | Fake.Core.FakeVar (5.20.3) 16 | Fake.Core.Context (>= 5.20.3) 17 | FSharp.Core (>= 4.7.2) 18 | Fake.Core.Process (5.20.3) 19 | Fake.Core.Environment (>= 5.20.3) 20 | Fake.Core.FakeVar (>= 5.20.3) 21 | Fake.Core.String (>= 5.20.3) 22 | Fake.Core.Trace (>= 5.20.3) 23 | Fake.IO.FileSystem (>= 5.20.3) 24 | FSharp.Core (>= 4.7.2) 25 | System.Collections.Immutable (>= 1.7.1) 26 | Fake.Core.SemVer (5.20.3) 27 | FSharp.Core (>= 4.7.2) 28 | Fake.Core.String (5.20.3) 29 | FSharp.Core (>= 4.7.2) 30 | Fake.Core.Target (5.20.3) 31 | Fake.Core.CommandLineParsing (>= 5.20.3) 32 | Fake.Core.Context (>= 5.20.3) 33 | Fake.Core.Environment (>= 5.20.3) 34 | Fake.Core.FakeVar (>= 5.20.3) 35 | Fake.Core.Process (>= 5.20.3) 36 | Fake.Core.String (>= 5.20.3) 37 | Fake.Core.Trace (>= 5.20.3) 38 | FSharp.Control.Reactive (>= 4.4.2) 39 | FSharp.Core (>= 4.7.2) 40 | Fake.Core.Tasks (5.20.3) 41 | Fake.Core.Trace (>= 5.20.3) 42 | FSharp.Core (>= 4.7.2) 43 | Fake.Core.Trace (5.20.3) 44 | Fake.Core.Environment (>= 5.20.3) 45 | Fake.Core.FakeVar (>= 5.20.3) 46 | FSharp.Core (>= 4.7.2) 47 | Fake.Core.Xml (5.20.3) 48 | Fake.Core.String (>= 5.20.3) 49 | FSharp.Core (>= 4.7.2) 50 | Fake.DotNet.Cli (5.20.3) 51 | Fake.Core.Environment (>= 5.20.3) 52 | Fake.Core.Process (>= 5.20.3) 53 | Fake.Core.String (>= 5.20.3) 54 | Fake.Core.Trace (>= 5.20.3) 55 | Fake.DotNet.MSBuild (>= 5.20.3) 56 | Fake.DotNet.NuGet (>= 5.20.3) 57 | Fake.IO.FileSystem (>= 5.20.3) 58 | FSharp.Core (>= 4.7.2) 59 | Mono.Posix.NETStandard (>= 1.0) 60 | Newtonsoft.Json (>= 12.0.3) 61 | Fake.DotNet.MSBuild (5.20.3) 62 | BlackFox.VsWhere (>= 1.1) 63 | Fake.Core.Environment (>= 5.20.3) 64 | Fake.Core.Process (>= 5.20.3) 65 | Fake.Core.String (>= 5.20.3) 66 | Fake.Core.Trace (>= 5.20.3) 67 | Fake.IO.FileSystem (>= 5.20.3) 68 | FSharp.Core (>= 4.7.2) 69 | MSBuild.StructuredLogger (>= 2.1.176) 70 | Fake.DotNet.NuGet (5.20.3) 71 | Fake.Core.Environment (>= 5.20.3) 72 | Fake.Core.Process (>= 5.20.3) 73 | Fake.Core.SemVer (>= 5.20.3) 74 | Fake.Core.String (>= 5.20.3) 75 | Fake.Core.Tasks (>= 5.20.3) 76 | Fake.Core.Trace (>= 5.20.3) 77 | Fake.Core.Xml (>= 5.20.3) 78 | Fake.IO.FileSystem (>= 5.20.3) 79 | Fake.Net.Http (>= 5.20.3) 80 | FSharp.Core (>= 4.7.2) 81 | Newtonsoft.Json (>= 12.0.3) 82 | NuGet.Protocol (>= 5.6) 83 | Fake.IO.FileSystem (5.20.3) 84 | Fake.Core.String (>= 5.20.3) 85 | FSharp.Core (>= 4.7.2) 86 | Fake.Net.Http (5.20.3) 87 | Fake.Core.Trace (>= 5.20.3) 88 | FSharp.Core (>= 4.7.2) 89 | FParsec (1.1.1) 90 | FSharp.Core (>= 4.3.4) 91 | FSharp.Control.Reactive (4.4.2) 92 | FSharp.Core (>= 4.7.2) 93 | System.Reactive (>= 4.4.1) 94 | FSharp.Core (4.7.2) 95 | Microsoft.Build (16.6) 96 | Microsoft.Build.Framework (16.6) 97 | System.Security.Permissions (>= 4.7) 98 | Microsoft.Build.Tasks.Core (16.6) 99 | Microsoft.Build.Framework (>= 16.6) 100 | Microsoft.Build.Utilities.Core (>= 16.6) 101 | Microsoft.Win32.Registry (>= 4.3) 102 | System.CodeDom (>= 4.4) 103 | System.Collections.Immutable (>= 1.5) 104 | System.Reflection.Metadata (>= 1.6) 105 | System.Reflection.TypeExtensions (>= 4.1) 106 | System.Resources.Extensions (>= 4.6) 107 | System.Security.Permissions (>= 4.7) 108 | System.Threading.Tasks.Dataflow (>= 4.9) 109 | Microsoft.Build.Tasks.Git (1.0) 110 | Microsoft.Build.Utilities.Core (16.6) 111 | Microsoft.Build.Framework (>= 16.6) 112 | Microsoft.Win32.Registry (>= 4.3) 113 | System.Collections.Immutable (>= 1.5) 114 | System.Security.Permissions (>= 4.7) 115 | System.Text.Encoding.CodePages (>= 4.0.1) 116 | Microsoft.NETCore.Platforms (3.1.3) 117 | Microsoft.NETCore.Targets (3.1) 118 | Microsoft.SourceLink.Common (1.0) 119 | Microsoft.SourceLink.GitHub (1.0) 120 | Microsoft.Build.Tasks.Git (>= 1.0) 121 | Microsoft.SourceLink.Common (>= 1.0) 122 | Microsoft.Win32.Primitives (4.3) 123 | Microsoft.NETCore.Platforms (>= 1.1) 124 | Microsoft.NETCore.Targets (>= 1.1) 125 | System.Runtime (>= 4.3) 126 | Microsoft.Win32.Registry (4.7) 127 | System.Buffers (>= 4.5) 128 | System.Memory (>= 4.5.3) 129 | System.Security.AccessControl (>= 4.7) 130 | System.Security.Principal.Windows (>= 4.7) 131 | Mono.Posix.NETStandard (1.0) 132 | MSBuild.StructuredLogger (2.1.176) 133 | Microsoft.Build (>= 16.4) 134 | Microsoft.Build.Framework (>= 16.4) 135 | Microsoft.Build.Tasks.Core (>= 16.4) 136 | Microsoft.Build.Utilities.Core (>= 16.4) 137 | Microsoft.SourceLink.GitHub (>= 1.0) 138 | Newtonsoft.Json (12.0.3) 139 | NuGet.Common (5.7) 140 | NuGet.Frameworks (>= 5.7) 141 | System.Diagnostics.Process (>= 4.3) 142 | System.Threading.Thread (>= 4.3) 143 | NuGet.Configuration (5.7) 144 | NuGet.Common (>= 5.7) 145 | System.Security.Cryptography.ProtectedData (>= 4.3) 146 | NuGet.Frameworks (5.7) 147 | NuGet.Packaging (5.7) 148 | Newtonsoft.Json (>= 9.0.1) 149 | NuGet.Configuration (>= 5.7) 150 | NuGet.Versioning (>= 5.7) 151 | System.Dynamic.Runtime (>= 4.3) 152 | System.Security.Cryptography.Cng (>= 5.0.0-preview.3.20214.6) 153 | System.Security.Cryptography.Pkcs (>= 5.0.0-preview.3.20214.6) 154 | NuGet.Protocol (5.7) 155 | NuGet.Packaging (>= 5.7) 156 | System.Dynamic.Runtime (>= 4.3) 157 | NuGet.Versioning (5.7) 158 | runtime.native.System (4.3.1) 159 | Microsoft.NETCore.Platforms (>= 1.1.1) 160 | Microsoft.NETCore.Targets (>= 1.1.3) 161 | System.Buffers (4.5.1) 162 | System.CodeDom (4.7) 163 | System.Collections (4.3) 164 | Microsoft.NETCore.Platforms (>= 1.1) 165 | Microsoft.NETCore.Targets (>= 1.1) 166 | System.Runtime (>= 4.3) 167 | System.Collections.Immutable (1.7.1) 168 | System.Memory (>= 4.5.4) 169 | System.Diagnostics.Debug (4.3) 170 | Microsoft.NETCore.Platforms (>= 1.1) 171 | Microsoft.NETCore.Targets (>= 1.1) 172 | System.Runtime (>= 4.3) 173 | System.Diagnostics.Process (4.3) 174 | Microsoft.NETCore.Platforms (>= 1.1) 175 | Microsoft.Win32.Primitives (>= 4.3) 176 | Microsoft.Win32.Registry (>= 4.3) 177 | runtime.native.System (>= 4.3) 178 | System.Collections (>= 4.3) 179 | System.Diagnostics.Debug (>= 4.3) 180 | System.Globalization (>= 4.3) 181 | System.IO (>= 4.3) 182 | System.IO.FileSystem (>= 4.3) 183 | System.IO.FileSystem.Primitives (>= 4.3) 184 | System.Resources.ResourceManager (>= 4.3) 185 | System.Runtime (>= 4.3) 186 | System.Runtime.Extensions (>= 4.3) 187 | System.Runtime.Handles (>= 4.3) 188 | System.Runtime.InteropServices (>= 4.3) 189 | System.Text.Encoding (>= 4.3) 190 | System.Text.Encoding.Extensions (>= 4.3) 191 | System.Threading (>= 4.3) 192 | System.Threading.Tasks (>= 4.3) 193 | System.Threading.Thread (>= 4.3) 194 | System.Threading.ThreadPool (>= 4.3) 195 | System.Dynamic.Runtime (4.3) 196 | System.Collections (>= 4.3) 197 | System.Diagnostics.Debug (>= 4.3) 198 | System.Linq (>= 4.3) 199 | System.Linq.Expressions (>= 4.3) 200 | System.ObjectModel (>= 4.3) 201 | System.Reflection (>= 4.3) 202 | System.Reflection.Emit (>= 4.3) 203 | System.Reflection.Emit.ILGeneration (>= 4.3) 204 | System.Reflection.Primitives (>= 4.3) 205 | System.Reflection.TypeExtensions (>= 4.3) 206 | System.Resources.ResourceManager (>= 4.3) 207 | System.Runtime (>= 4.3) 208 | System.Runtime.Extensions (>= 4.3) 209 | System.Threading (>= 4.3) 210 | System.Formats.Asn1 (5.0.0-preview.8.20407.11) 211 | System.Buffers (>= 4.5.1) 212 | System.Memory (>= 4.5.4) 213 | System.Globalization (4.3) 214 | Microsoft.NETCore.Platforms (>= 1.1) 215 | Microsoft.NETCore.Targets (>= 1.1) 216 | System.Runtime (>= 4.3) 217 | System.IO (4.3) 218 | Microsoft.NETCore.Platforms (>= 1.1) 219 | Microsoft.NETCore.Targets (>= 1.1) 220 | System.Runtime (>= 4.3) 221 | System.Text.Encoding (>= 4.3) 222 | System.Threading.Tasks (>= 4.3) 223 | System.IO.FileSystem (4.3) 224 | Microsoft.NETCore.Platforms (>= 1.1) 225 | Microsoft.NETCore.Targets (>= 1.1) 226 | System.IO (>= 4.3) 227 | System.IO.FileSystem.Primitives (>= 4.3) 228 | System.Runtime (>= 4.3) 229 | System.Runtime.Handles (>= 4.3) 230 | System.Text.Encoding (>= 4.3) 231 | System.Threading.Tasks (>= 4.3) 232 | System.IO.FileSystem.Primitives (4.3) 233 | System.Runtime (>= 4.3) 234 | System.Linq (4.3) 235 | System.Collections (>= 4.3) 236 | System.Diagnostics.Debug (>= 4.3) 237 | System.Resources.ResourceManager (>= 4.3) 238 | System.Runtime (>= 4.3) 239 | System.Runtime.Extensions (>= 4.3) 240 | System.Linq.Expressions (4.3) 241 | System.Collections (>= 4.3) 242 | System.Diagnostics.Debug (>= 4.3) 243 | System.Globalization (>= 4.3) 244 | System.IO (>= 4.3) 245 | System.Linq (>= 4.3) 246 | System.ObjectModel (>= 4.3) 247 | System.Reflection (>= 4.3) 248 | System.Reflection.Emit (>= 4.3) 249 | System.Reflection.Emit.ILGeneration (>= 4.3) 250 | System.Reflection.Emit.Lightweight (>= 4.3) 251 | System.Reflection.Extensions (>= 4.3) 252 | System.Reflection.Primitives (>= 4.3) 253 | System.Reflection.TypeExtensions (>= 4.3) 254 | System.Resources.ResourceManager (>= 4.3) 255 | System.Runtime (>= 4.3) 256 | System.Runtime.Extensions (>= 4.3) 257 | System.Threading (>= 4.3) 258 | System.Memory (4.5.4) 259 | System.Buffers (>= 4.5.1) 260 | System.Numerics.Vectors (>= 4.4) 261 | System.Runtime.CompilerServices.Unsafe (>= 4.5.3) 262 | System.Numerics.Vectors (4.5) 263 | System.ObjectModel (4.3) 264 | System.Collections (>= 4.3) 265 | System.Diagnostics.Debug (>= 4.3) 266 | System.Resources.ResourceManager (>= 4.3) 267 | System.Runtime (>= 4.3) 268 | System.Threading (>= 4.3) 269 | System.Reactive (4.4.1) 270 | System.Runtime.InteropServices.WindowsRuntime (>= 4.3) 271 | System.Threading.Tasks.Extensions (>= 4.5.4) 272 | System.Reflection (4.3) 273 | Microsoft.NETCore.Platforms (>= 1.1) 274 | Microsoft.NETCore.Targets (>= 1.1) 275 | System.IO (>= 4.3) 276 | System.Reflection.Primitives (>= 4.3) 277 | System.Runtime (>= 4.3) 278 | System.Reflection.Emit (4.7) 279 | System.Reflection.Emit.ILGeneration (>= 4.7) 280 | System.Reflection.Emit.ILGeneration (4.7) 281 | System.Reflection.Emit.Lightweight (4.7) 282 | System.Reflection.Emit.ILGeneration (>= 4.7) 283 | System.Reflection.Extensions (4.3) 284 | Microsoft.NETCore.Platforms (>= 1.1) 285 | Microsoft.NETCore.Targets (>= 1.1) 286 | System.Reflection (>= 4.3) 287 | System.Runtime (>= 4.3) 288 | System.Reflection.Metadata (1.8.1) 289 | System.Collections.Immutable (>= 1.7.1) 290 | System.Reflection.Primitives (4.3) 291 | Microsoft.NETCore.Platforms (>= 1.1) 292 | Microsoft.NETCore.Targets (>= 1.1) 293 | System.Runtime (>= 4.3) 294 | System.Reflection.TypeExtensions (4.7) 295 | System.Resources.Extensions (4.7.1) 296 | System.Memory (>= 4.5.4) 297 | System.Resources.ResourceManager (4.3) 298 | Microsoft.NETCore.Platforms (>= 1.1) 299 | Microsoft.NETCore.Targets (>= 1.1) 300 | System.Globalization (>= 4.3) 301 | System.Reflection (>= 4.3) 302 | System.Runtime (>= 4.3) 303 | System.Runtime (4.3.1) 304 | Microsoft.NETCore.Platforms (>= 1.1.1) 305 | Microsoft.NETCore.Targets (>= 1.1.3) 306 | System.Runtime.CompilerServices.Unsafe (4.7.1) 307 | System.Runtime.Extensions (4.3.1) 308 | Microsoft.NETCore.Platforms (>= 1.1.1) 309 | Microsoft.NETCore.Targets (>= 1.1.3) 310 | System.Runtime (>= 4.3.1) 311 | System.Runtime.Handles (4.3) 312 | Microsoft.NETCore.Platforms (>= 1.1) 313 | Microsoft.NETCore.Targets (>= 1.1) 314 | System.Runtime (>= 4.3) 315 | System.Runtime.InteropServices (4.3) 316 | Microsoft.NETCore.Platforms (>= 1.1) 317 | Microsoft.NETCore.Targets (>= 1.1) 318 | System.Reflection (>= 4.3) 319 | System.Reflection.Primitives (>= 4.3) 320 | System.Runtime (>= 4.3) 321 | System.Runtime.Handles (>= 4.3) 322 | System.Runtime.InteropServices.WindowsRuntime (4.3) 323 | System.Runtime (>= 4.3) 324 | System.Security.AccessControl (4.7) 325 | System.Security.Principal.Windows (>= 4.7) 326 | System.Security.Cryptography.Cng (5.0.0-preview.8.20407.11) 327 | System.Security.Cryptography.Pkcs (5.0.0-preview.8.20407.11) 328 | System.Buffers (>= 4.5.1) 329 | System.Formats.Asn1 (>= 5.0.0-preview.8.20407.11) 330 | System.Memory (>= 4.5.4) 331 | System.Security.Cryptography.Cng (>= 5.0.0-preview.8.20407.11) 332 | System.Security.Cryptography.ProtectedData (4.7) 333 | System.Memory (>= 4.5.3) 334 | System.Security.Permissions (4.7) 335 | System.Security.AccessControl (>= 4.7) 336 | System.Security.Principal.Windows (4.7) 337 | System.Text.Encoding (4.3) 338 | Microsoft.NETCore.Platforms (>= 1.1) 339 | Microsoft.NETCore.Targets (>= 1.1) 340 | System.Runtime (>= 4.3) 341 | System.Text.Encoding.CodePages (4.7.1) 342 | System.Runtime.CompilerServices.Unsafe (>= 4.7.1) 343 | System.Text.Encoding.Extensions (4.3) 344 | Microsoft.NETCore.Platforms (>= 1.1) 345 | Microsoft.NETCore.Targets (>= 1.1) 346 | System.Runtime (>= 4.3) 347 | System.Text.Encoding (>= 4.3) 348 | System.Threading (4.3) 349 | System.Runtime (>= 4.3) 350 | System.Threading.Tasks (>= 4.3) 351 | System.Threading.Tasks (4.3) 352 | Microsoft.NETCore.Platforms (>= 1.1) 353 | Microsoft.NETCore.Targets (>= 1.1) 354 | System.Runtime (>= 4.3) 355 | System.Threading.Tasks.Dataflow (4.11.1) 356 | System.Threading.Tasks.Extensions (4.5.4) 357 | System.Runtime.CompilerServices.Unsafe (>= 4.5.3) 358 | System.Threading.Thread (4.3) 359 | System.Runtime (>= 4.3) 360 | System.Threading.ThreadPool (4.3) 361 | System.Runtime (>= 4.3) 362 | System.Runtime.Handles (>= 4.3) 363 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _public/ 2 | content/*.autogen.fs 3 | -------------------------------------------------------------------------------- /docs/_lib/Fornax.Core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davnavr/FSharpWrap/a2f22c05c26de29796917d4bd24c65fcc2035cbf/docs/_lib/Fornax.Core.dll -------------------------------------------------------------------------------- /docs/config.fsx: -------------------------------------------------------------------------------- 1 | #r "./_lib/Fornax.Core.dll" 2 | #r "../packages/documentation/FSharp.Formatting/lib/netstandard2.0/FSharp.Formatting.Common.dll" 3 | 4 | open Config 5 | open System.IO 6 | 7 | let config = { 8 | Generators = [ 9 | let page (file: string) = 10 | let name = Path.GetFileNameWithoutExtension file |> sprintf "%s.html" 11 | let dir = Path.GetDirectoryName file |> Path.GetDirectoryName 12 | Path.Combine(dir, name) 13 | 14 | let stat (_: string, page: string) = 15 | (page.StartsWith "style" && page.EndsWith ".css") || (page.StartsWith "js" && page.EndsWith ".js") 16 | 17 | let literate (_: string, page: string) = 18 | page.EndsWith ".fsx" && page.StartsWith "content" 19 | 20 | { Script = "page.fsx"; Trigger = OnFilePredicate literate; OutputFile = Custom page } 21 | { Script = "static.fsx"; Trigger = OnFilePredicate stat; OutputFile = SameFileName } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /docs/content/FSharpWrap.Documentation.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | netstandard2.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/content/collection-computation-expressions.fsx: -------------------------------------------------------------------------------- 1 | (*** hide ***) 2 | (* 3 | index=4 4 | *) 5 | #r "../../packages/documentation/System.Collections.Immutable/lib/netstandard2.0/System.Collections.Immutable.dll" 6 | #load "../content/output.autogen.fs" 7 | (** 8 | # Collection Computation Expressions 9 | 10 | FSharpWrap automatically generates [computation expressions](https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/computation-expressions) 11 | for immutable and mutable collection types that implement [`IEnumerable<'T>`](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerable-1). 12 | 13 | ## Conditionally Generated Methods 14 | 15 | These methods are only generated for the computation expression type when a 16 | specific member is defined on the collection type. 17 | 18 | ### `Yield` method 19 | In order for a generated computation expression to be usable, collection types 20 | need at least an `Add`, `Push`, or `Enqueue` method that takes onle one 21 | parameters with a return type either equal to the type of the collection or 22 | `void`. 23 | 24 | For dictionary types, an `Add` method that takes two parameters instead of one 25 | is also allowed. 26 | *) 27 | open System.Collections.Immutable 28 | open System.Collections.Generic 29 | 30 | // Mutable type 31 | let a = 32 | List.expr { 33 | 0 // Uses `Add` method under the hood 34 | 1 35 | 2 36 | } 37 | |> Array.ofSeq // Allow the items to be seen in the output 38 | 39 | let b = 40 | ImmutableList.expr { 41 | 3 // Uses an immutable `Add` method under the hood 42 | 4 43 | 5 44 | } 45 | |> Array.ofSeq 46 | 47 | let c = 48 | ImmutableDictionary.expr { 49 | yield "hello", "world" // Uses an `Add` method with two parameters 50 | yield "triglycerides", "fatty acid" 51 | yield "key", "value" 52 | } 53 | |> Array.ofSeq 54 | (*** include-fsi-output ***) 55 | (** 56 | ### `YieldFrom` method 57 | Only defined when the collection type defines an `AddRange` method that takes 58 | only one parameter. 59 | *) 60 | open System.Collections.Immutable 61 | 62 | let d = 63 | ImmutableList.expr { 64 | yield! b 65 | } 66 | |> Array.ofSeq 67 | (*** include-fsi-output ***) 68 | (** 69 | ### `Zero` method 70 | Defined when the collection type defines a parameterless constructor or defines 71 | a static field named `Empty` with a type that is the same as the collection type. 72 | *) 73 | open System.Collections.Immutable 74 | 75 | let e = 76 | ImmutableList.expr { 77 | if 1 = 0 then 78 | yield 1 79 | // `Empty` field is being used here 80 | } 81 | |> Array.ofSeq 82 | (*** include-fsi-output ***) 83 | (** 84 | ## Always Generated Methods 85 | 86 | These methods are always generated no matter what 87 | members are defined on the collection type. 88 | 89 | ## `For` method 90 | 91 | Allows the use of [`for` loops](https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/loops-for-to-expression) 92 | inside the computation expression. 93 | *) 94 | open System 95 | 96 | let f = 97 | ImmutableList.expr { 98 | for i = 97 to 102 do char i 99 | } 100 | |> String.Concat 101 | (*** include-fsi-output ***) 102 | (** 103 | `TryFinally` method 104 | 105 | Allows the use of a [`try...finally` expression](https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/exception-handling/the-try-finally-expression) 106 | within the computation expression. 107 | *) 108 | open System.Collections.Immutable 109 | 110 | let g = 111 | ImmutableList.expr { 112 | try 113 | 1 114 | 2 115 | 3 116 | finally 117 | printfn "Hello" 118 | } 119 | |> Array.ofSeq 120 | (*** include-fsi-output ***) 121 | (** 122 | `Using` method 123 | 124 | Allows the use of [`use` bindings](https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/resource-management-the-use-keyword#use-binding) 125 | within the computation expression. 126 | *) 127 | open System 128 | open System.IO 129 | open System.Collections.Immutable 130 | 131 | let h = 132 | ImmutableList.expr { 133 | use stream = new MemoryStream(16) 134 | stream.Write(Array.replicate 16 5uy, 0, 16) 135 | yield! stream.GetBuffer() 136 | } 137 | |> Array.ofSeq 138 | (*** include-fsi-output ***) 139 | -------------------------------------------------------------------------------- /docs/content/getting-started.fsx: -------------------------------------------------------------------------------- 1 | (*** hide ***) 2 | (* 3 | index=1 4 | *) 5 | #r "../../packages/documentation/System.Collections.Immutable/lib/netstandard2.0/System.Collections.Immutable.dll" 6 | #load "../content/output.autogen.fs" 7 | (** 8 | # Getting started 9 | 10 | ## Installing the package 11 | 12 | To install the latest version of FSharpWrap using the 13 | [.NET CLI](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-add-package), 14 | use the following: 15 | 16 | ```bash 17 | dotnet add package FSharpWrap 18 | ``` 19 | 20 | ## Using generated code 21 | 22 | In order to use the generated code in your project, add the following element 23 | to your project file in an `` above all other `` items: 24 | 25 | ```xml 26 | 27 | ``` 28 | 29 | Because the generated code is quite large by default, the following should also 30 | be added to a `.gitignore` file: 31 | 32 | ```text 33 | *.autogen.fs 34 | ``` 35 | 36 | Any instance methods, constructors, instance read-only fields, and get-only 37 | properties on classes and immutable structs will then have F# functions, active 38 | patterns, or [computation expressions](./collection-computation-expressions) generated for them. 39 | *) 40 | open System.Collections.Generic 41 | open System.Collections.Immutable 42 | 43 | // Constructors 44 | let stack: Stack<_> = [ 1..10 ] |> Stack.ofSeq 45 | 46 | // Instance method call 47 | let a: bool = Stack.contains 5 stack 48 | 49 | // Get-only properties 50 | let b: int = Stack.count stack 51 | let c: string = 52 | let nums = stack.ToImmutableList() 53 | match nums with 54 | | ImmutableList.IsEmpty -> "read-only" 55 | | _ -> "not read-only" 56 | 57 | // Computation expressions 58 | let d: Stack<_> = 59 | Stack.expr { 60 | for num in stack do num 61 | 11; 62 | 12; 63 | 13; 64 | } 65 | 66 | d :> seq<_> |> printfn "d is %A" 67 | (*** include-output ***) 68 | (** 69 | ## Filtering generated code 70 | 71 | FSharpWrap allows entire assemblies and namespaces to be included or excluded 72 | from code generation, which helps reduce compilation times by generating only 73 | code that you will use. Note that assemblies can only either be included or 74 | excluded, and that namespaces can only either be included or excluded. 75 | 76 | To only include certain assemblies in code generation, use the following: 77 | ```xml 78 | 79 | 80 | 81 | 82 | ``` 83 | 84 | To only exclude certain assemblies from code generation, use the following: 85 | 86 | ```xml 87 | 88 | 89 | 90 | ``` 91 | 92 | Following the inclusion or exclusion of assemblies, FSharpWrap will also 93 | include or exclude any specified namespaces. Note that in order to include or 94 | exclude any "child" namespaces, their names must be specified as well. 95 | 96 | To only include the types in certain namespaces, use the following: 97 | ```xml 98 | 99 | 100 | 101 | ``` 102 | 103 | To only exclude types in certain namespaces, use the following: 104 | ```xml 105 | 106 | 107 | 108 | 109 | ``` 110 | 111 | ## Code Generation Limitations 112 | Only public members are included in code generation. 113 | 114 | Currently, any non-readonly structs (structs not marked 115 | [`IsReadOnly`](https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/structures#readonly-structs) in F#) 116 | are excluded from code generation. 117 | *) 118 | -------------------------------------------------------------------------------- /docs/content/index.fsx: -------------------------------------------------------------------------------- 1 | (*** hide ***) 2 | (* 3 | index=0 4 | *) 5 | #r "../../packages/documentation/System.Collections.Immutable/lib/netstandard2.0/System.Collections.Immutable.dll" 6 | #load "../content/output.autogen.fs" 7 | (** 8 | # Overview 9 | 10 | FSharpWrap generates F# functions and active patterns for your dependencies, 11 | reducing the amount of F# code you need to write just to use code written 12 | in other .NET languages. 13 | 14 | ## Example 15 | *) 16 | open System.Collections.Immutable 17 | 18 | let original = ImmutableList.CreateRange [| 1; 5; 9 |] 19 | 20 | // Currying! 21 | let add2 = ImmutableList.add 2 22 | let copy = add2 original 23 | 24 | // Computation Expressions 25 | let example = 26 | ImmutableList.expr { 27 | 3 28 | 1 29 | 4 30 | yield! copy 31 | } 32 | 33 | printfn "%A" example 34 | (*** include-output ***) 35 | (** 36 | ## Tutorial 37 | 38 | Click [here](./getting-started.html) to get started with using FSharpWrap. 39 | *) 40 | -------------------------------------------------------------------------------- /docs/content/msbuild.fsx: -------------------------------------------------------------------------------- 1 | (*** hide ***) 2 | (* 3 | index=3 4 | *) 5 | (** 6 | # MSBuild properties and items 7 | 8 | FSharpWrap offers several properties and items to configure how it generates 9 | code. 10 | 11 | ## Items 12 | ### `` `` 13 | Specifies the names of the assemblies to include or exclude from code 14 | generation. By default, all assemblies are included in code generation. 15 | Using both items is an error. 16 | 17 | ### `` `` 18 | Specifies the namespaces to included or exclude from code generation. By default, 19 | all namespaces are included in code generation. Using both items is an error. 20 | 21 | ## Properties 22 | ### `` 23 | The path to the output file containing the generated F# code. Defaults to 24 | `$(MSBuildProjectDirectory)/output.autogen.fs` for projects with a single 25 | `` or `$(MSBuildProjectDirectory)/output.$(TargetFramework).autogen.fs` 26 | for projects using ``. 27 | 28 | ### `<_FSharpWrapLaunchDebugger>` 29 | Property for internal use. If set to `true`, calls 30 | [Debugger.Launch](https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.debugger.launch). 31 | *) 32 | -------------------------------------------------------------------------------- /docs/content/multi-target.fsx: -------------------------------------------------------------------------------- 1 | (*** hide ***) 2 | (* 3 | index=2 4 | *) 5 | (** 6 | # Using multiple target frameworks 7 | 8 | By default, FSharpWrap will generate different files for each target framework 9 | used in your project. 10 | 11 | ## Code generation defaults 12 | 13 | If only one target framework is specified using the `` 14 | element, then the generated code is in a file named `output.autogen.fs` in 15 | the current project directory. However, if multiple target frameworks are 16 | specified using the 17 | [``](https://docs.microsoft.com/en-us/nuget/create-packages/multiple-target-frameworks-project-file) 18 | element, then the path to each generated code file relative to the project 19 | directory is `output.$(TargetFramework).autogen.fs`, where 20 | `$(TargetFramework)` is the corresponding target framework moniker. 21 | 22 | ## Changing the file name 23 | 24 | If you are only using one target framework, you can change the path to the 25 | generated code file using the `` property. 26 | 27 | ```xml 28 | 29 | Some/Other/Directory/MyCustomFileName.autogen.fs 30 | 31 | ``` 32 | 33 | If using multiple target frameworks, consider inserting the 34 | `$(TargetFramework)` in part of the path to the output file. 35 | 36 | ```xml 37 | 38 | CustomDirectory/MyCustomFileName.$(TargetFramework).autogen.fs 39 | 40 | ``` 41 | *) 42 | -------------------------------------------------------------------------------- /docs/content/paket.references: -------------------------------------------------------------------------------- 1 | FSharp.Core 2 | group Documentation 3 | System.Collections.Immutable 4 | -------------------------------------------------------------------------------- /docs/generators/page.fsx: -------------------------------------------------------------------------------- 1 | #r "../_lib/Fornax.Core.dll" 2 | #r "../../packages/documentation/FSharp.Formatting/lib/netstandard2.0/FSharp.Formatting.Common.dll" 3 | #if !FORNAX 4 | #load "../loaders/article.fsx" 5 | #endif 6 | 7 | open System.IO 8 | 9 | open Html 10 | 11 | let generate (content: SiteContents) (root: string) (page: string) = 12 | let articles = 13 | content.TryGetValues() |> Option.defaultValue Seq.empty 14 | let page' = 15 | let path = Path.GetFullPath page 16 | Seq.find 17 | (fun (article: Article.Info) -> article.File.FullName = path) 18 | articles 19 | html [] [ 20 | head [] [ 21 | meta [ CharSet "utf-8" ] 22 | meta [ Name "viewport"; Content "width=device-width, initial-scale=1" ] 23 | Html.title [] [ !!(sprintf "FSharpWrap - %s" page'.Title) ] 24 | link [ Rel "stylesheet"; Href "./style/main.css" ] 25 | link [ Rel "stylesheet"; Href "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.4.0/styles/vs2015.min.css" ] 26 | script [ Src "./js/codecopy.js" ] [] 27 | script [ Src "./js/highlight.js" ] [] 28 | ] 29 | 30 | body [] [ 31 | nav [ Class "navbar infobar" ] [ 32 | let link url title = 33 | a [ Class "navbar__link"; Href url ] [ !!title ] 34 | 35 | h1 [] [ !!"FSharpWrap" ] 36 | 37 | ul [ Class "navbar__urls" ] [ 38 | let articles' = Seq.sortBy (fun { Article.Info.Index = i } -> i) articles 39 | 40 | for article in articles' do 41 | let url = "." + article.Link 42 | let liclass = 43 | if article = page' 44 | then [ Class "navbar__selected" ] 45 | else [] 46 | li liclass [ link url article.Title ] 47 | ] 48 | 49 | h2 [ Class "navbar__title" ] [ !!"Links" ] 50 | 51 | ul [ Class "navbar__urls" ] [ 52 | li [] [ link "https://github.com/davnavr/FSharpWrap" "GitHub" ] 53 | li [] [ link "https://www.nuget.org/packages/FSharpWrap/" "NuGet" ] 54 | ] 55 | ] 56 | 57 | main [ Class "article" ] [ 58 | !!page'.Content 59 | ] 60 | 61 | aside [ Class "tocbar infobar" ] [ 62 | h3 [] [ !!"Contents" ] 63 | 64 | ul [ Class "tocbar__contents" ] [ 65 | for section in page'.Sections do 66 | let url = 67 | section.Replace(' ', '-') |> sprintf "#%s" 68 | li [] [ 69 | a [ Class "tocbar__link"; Href url ] [ !!section ] 70 | ] 71 | ] 72 | ] 73 | ] 74 | ] 75 | |> HtmlElement.ToString 76 | -------------------------------------------------------------------------------- /docs/generators/static.fsx: -------------------------------------------------------------------------------- 1 | #r "../_lib/Fornax.Core.dll" 2 | 3 | open Html 4 | open System.IO 5 | 6 | let generate (content: SiteContents) (root: string) (page: string) = 7 | Path.Combine(root, page) |> File.ReadAllBytes 8 | -------------------------------------------------------------------------------- /docs/js/codecopy.js: -------------------------------------------------------------------------------- 1 | // Adds a "copy" button to code blocks 2 | 3 | window.addEventListener("load", (_event) => { 4 | let blocks = document.body.querySelectorAll(".article pre code"); 5 | for (let i = 0; i < blocks.length; i++) { 6 | let code = blocks.item(i); 7 | let contents = code.innerText 8 | let button = document.createElement("button"); 9 | button.innerHTML = "Copy"; 10 | button.classList.add("code__copy-button"); 11 | button.onclick = () => { 12 | navigator.clipboard.writeText(contents); 13 | }; 14 | code.insertAdjacentElement("beforebegin", button); 15 | } 16 | }); 17 | -------------------------------------------------------------------------------- /docs/js/highlight.js: -------------------------------------------------------------------------------- 1 | // Adds color to code blocks using CSS classes used in highlight.js 2 | 3 | window.addEventListener("load", (_event) => { 4 | let blocks = document.body.querySelectorAll("pre code"); 5 | for (let i = 0; i < blocks.length; i++) { 6 | let pre = blocks.item(i); 7 | pre.classList.add("hljs"); 8 | } 9 | }); 10 | -------------------------------------------------------------------------------- /docs/loaders/article.fsx: -------------------------------------------------------------------------------- 1 | #r "../_lib/Fornax.Core.dll" 2 | #r "../../packages/documentation/FSharp.Formatting/lib/netstandard2.0/FSharp.Formatting.Markdown.dll" 3 | #r "../../packages/documentation/FSharp.Formatting/lib/netstandard2.0/FSharp.Formatting.CodeFormat.dll" 4 | #r "../../packages/documentation/FSharp.Formatting/lib/netstandard2.0/FSharp.Formatting.Common.dll" 5 | #r "../../packages/documentation/FSharp.Formatting/lib/netstandard2.0/FSharp.Formatting.Literate.dll" 6 | 7 | open System 8 | open System.IO 9 | 10 | open FSharp.Formatting.CodeFormat 11 | open FSharp.Formatting.Literate 12 | open FSharp.Formatting.Literate.Evaluation 13 | open FSharp.Formatting.Markdown 14 | 15 | type Info = 16 | { Category: string 17 | Content: string 18 | File: FileInfo 19 | Index: int 20 | Link: string 21 | Sections: string list 22 | Title: string } 23 | 24 | let private (|IsHeader|_|) size = 25 | function 26 | | Heading(size', [ Literal(text, _) ], _) when size' = size -> Some text 27 | | _ -> None 28 | 29 | let private (|IsLiterateCode|_|) (ps: MarkdownEmbedParagraphs) = 30 | match ps with 31 | | :? LiterateParagraph as p -> Some p 32 | | _ -> None 33 | 34 | let private (|HasConfig|_|) = 35 | function 36 | | Line("(*", _) :: Line(config, _) :: Line("*)", _) :: _ -> 37 | let config' = config.Split ';' 38 | {| Index = 39 | Array.tryPick 40 | (fun (str: string) -> 41 | if str.StartsWith "index=" then 42 | str.Substring(6) 43 | |> Int32.Parse 44 | |> Some 45 | else 46 | None) 47 | config' 48 | |> Option.defaultValue Int32.MaxValue 49 | Category = "" |} 50 | |> Some 51 | | _ -> None 52 | 53 | let highlight = 54 | function 55 | | TokenKind.Keyword -> "hljs-keyword" 56 | | TokenKind.String -> "hljs-string" 57 | | TokenKind.Comment -> "hljs-comment" 58 | | TokenKind.Property 59 | | TokenKind.Identifier -> "hljs-title" 60 | | TokenKind.TypeArgument 61 | | TokenKind.Number -> "hljs-number" 62 | | TokenKind.Operator 63 | | TokenKind.Punctuation -> "hljs-punctuation" 64 | | TokenKind.Inactive 65 | | TokenKind.Preprocessor -> "hljs-meta" 66 | | TokenKind.Pattern 67 | | TokenKind.Function -> "hljs-function" 68 | | TokenKind.Module 69 | | TokenKind.ReferenceType 70 | | TokenKind.ValueType 71 | | TokenKind.Enumeration 72 | | TokenKind.UnionCase 73 | | TokenKind.Interface -> "hljs-type" 74 | | TokenKind.MutableVar 75 | | TokenKind.Disposable 76 | | TokenKind.Printf 77 | | TokenKind.Escaped -> "hljs-regexp" 78 | | TokenKind.Default -> "" 79 | 80 | let loader (root: string) (ctx: SiteContents) = 81 | try 82 | let dir = Path.Combine(root, "content") |> DirectoryInfo 83 | let fsi = FsiEvaluator() 84 | for script in dir.GetFiles "*.fsx" do 85 | let doc = Literate.ParseAndCheckScriptFile(script.FullName, fsiEvaluator = fsi) 86 | let config = 87 | match List.head doc.Paragraphs with 88 | | EmbedParagraphs(IsLiterateCode(LiterateCode(HasConfig config, _, _)), _) -> 89 | config 90 | | _ -> {| Index = Int32.MaxValue; Category = "" |} 91 | ctx.Add 92 | { Category = config.Category 93 | Content = 94 | Literate.ToHtml ( 95 | doc, 96 | generateAnchors = true, 97 | tokenKindToCss = highlight 98 | ) 99 | File = script 100 | Index = config.Index 101 | Link = 102 | Path.GetFileNameWithoutExtension script.FullName |> sprintf "/%s.html" 103 | Sections = 104 | List.choose 105 | (function 106 | | IsHeader 2 text -> Some text 107 | | _ -> None) 108 | doc.Paragraphs 109 | Title = 110 | List.pick 111 | (function 112 | | IsHeader 1 text -> Some text 113 | | _ -> None) 114 | doc.Paragraphs } 115 | ctx 116 | with 117 | | ex -> stderr.WriteLine ex; raise ex 118 | -------------------------------------------------------------------------------- /docs/style/main.css: -------------------------------------------------------------------------------- 1 | 2 | html, body { 3 | font-family: Verdana, Geneva, sans-serif; 4 | font-size: 16px; 5 | margin: 0; 6 | } 7 | 8 | .article { 9 | overflow-x: hidden; 10 | padding: 20px; 11 | position: relative; 12 | } 13 | 14 | .article h1 a, .article h2 a, .article h3 a { 15 | color: #000000; 16 | text-decoration: none; 17 | } 18 | 19 | .infobar { 20 | box-sizing: border-box; 21 | display: none; 22 | height: 100%; 23 | margin: 0; 24 | padding: 0px 10px 0px 10px; 25 | position: fixed; 26 | top: 0; 27 | } 28 | 29 | .infobar ul li { 30 | padding: 5px; 31 | } 32 | 33 | .infobar__link:link, .infobar__link:visited { 34 | text-decoration: none; 35 | } 36 | 37 | .infobar__link:hover, .infobar__link:active { 38 | text-decoration: underline; 39 | } 40 | 41 | .navbar { 42 | background-color: #35464f; 43 | color: #ffffff; 44 | width: 300px; 45 | } 46 | 47 | .tocbar { 48 | right: 0; 49 | top: 0; 50 | width: 200px; 51 | } 52 | 53 | @media screen and (min-width: 900px) { 54 | .article { 55 | margin-left: 300px; 56 | margin-right: 200px; 57 | } 58 | 59 | .infobar { 60 | display: block; 61 | } 62 | } 63 | 64 | .navbar__urls { 65 | list-style-type: none; 66 | padding: 0; 67 | } 68 | 69 | .navbar__selected { 70 | background-color: #447087; 71 | } 72 | 73 | .navbar__link { 74 | color: #ffffff; 75 | } 76 | 77 | .navbar__title { 78 | color: #aaaaaa; 79 | font-weight: normal; 80 | } 81 | 82 | .tocbar__contents { 83 | list-style-type: square; 84 | padding: 0; 85 | } 86 | 87 | .tocbar__link { 88 | color: #000000; 89 | text-decoration: none; 90 | } 91 | 92 | .code__copy-button { 93 | position: absolute; 94 | right: 23px; 95 | } 96 | 97 | .fsdocs-tip { 98 | display: none; 99 | } 100 | 101 | td.snippet { 102 | width: 100%; 103 | } 104 | 105 | table.pre { 106 | display: flex; 107 | overflow-x: auto; 108 | table-layout: fixed; 109 | } 110 | 111 | h1 { 112 | font-weight: 200; 113 | } 114 | 115 | h2, h3 { 116 | font-weight: 400; 117 | } 118 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "5.0.100", 4 | "rollForward": "latestFeature" 5 | } 6 | } -------------------------------------------------------------------------------- /paket.dependencies: -------------------------------------------------------------------------------- 1 | framework: netcoreapp3.1 2 | storage: packages 3 | source https://api.nuget.org/v3/index.json 4 | 5 | nuget FSharp.Core 6 | nuget System.Reflection.MetadataLoadContext 7 | 8 | group Documentation 9 | framework: netstandard2.0 10 | storage: packages 11 | source https://api.nuget.org/v3/index.json 12 | 13 | nuget FSharp.Formatting 14 | nuget Markdig 15 | nuget System.Collections.Immutable 16 | 17 | group Test 18 | framework: net5.0, netcoreapp3.1, netstandard2.0 19 | storage: none 20 | source https://api.nuget.org/v3/index.json 21 | 22 | nuget BenchmarkDotNet 23 | nuget Expecto 24 | nuget Expecto.FsCheck 25 | nuget System.Collections.Immutable 26 | -------------------------------------------------------------------------------- /paket.lock: -------------------------------------------------------------------------------- 1 | STORAGE: PACKAGES 2 | RESTRICTION: == netcoreapp3.1 3 | NUGET 4 | remote: https://api.nuget.org/v3/index.json 5 | FSharp.Core (5.0) 6 | System.Reflection.MetadataLoadContext (5.0) 7 | 8 | GROUP Documentation 9 | STORAGE: PACKAGES 10 | RESTRICTION: == netstandard2.0 11 | NUGET 12 | remote: https://api.nuget.org/v3/index.json 13 | FSharp.Compiler.Service (38.0) 14 | FSharp.Core (5.0) 15 | FSharp.Core (5.0) 16 | FSharp.Formatting (7.2.9) 17 | FSharp.Compiler.Service (>= 36.0.3) 18 | Markdig (0.22.1) 19 | System.Memory (>= 4.5.4) 20 | System.Buffers (4.5.1) 21 | System.Collections.Immutable (5.0) 22 | System.Memory (>= 4.5.4) 23 | System.Memory (4.5.4) 24 | System.Buffers (>= 4.5.1) 25 | System.Numerics.Vectors (>= 4.4) 26 | System.Runtime.CompilerServices.Unsafe (>= 4.5.3) 27 | System.Numerics.Vectors (4.5) 28 | System.Runtime.CompilerServices.Unsafe (5.0) 29 | 30 | GROUP Test 31 | STORAGE: NONE 32 | RESTRICTION: || (== net50) (== netcoreapp3.1) (== netstandard2.0) 33 | NUGET 34 | remote: https://api.nuget.org/v3/index.json 35 | BenchmarkDotNet (0.12.1) 36 | BenchmarkDotNet.Annotations (>= 0.12.1) 37 | CommandLineParser (>= 2.4.3) 38 | Iced (>= 1.4) 39 | Microsoft.CodeAnalysis.CSharp (>= 2.10) 40 | Microsoft.Diagnostics.NETCore.Client (>= 0.2.61701) 41 | Microsoft.Diagnostics.Runtime (>= 1.1.57604) 42 | Microsoft.Diagnostics.Tracing.TraceEvent (>= 2.0.49) 43 | Microsoft.DotNet.PlatformAbstractions (>= 2.1) 44 | Microsoft.Win32.Registry (>= 4.5) 45 | Perfolizer (>= 0.2.1) 46 | System.Management (>= 4.5) 47 | System.Reflection.Emit (>= 4.3) 48 | System.Reflection.Emit.Lightweight (>= 4.3) 49 | System.Threading.Tasks.Extensions (>= 4.5.2) 50 | System.ValueTuple (>= 4.5) 51 | BenchmarkDotNet.Annotations (0.12.1) 52 | CommandLineParser (2.8) 53 | Expecto (9.0.2) 54 | FSharp.Core (>= 4.6) 55 | Mono.Cecil (>= 0.11.2) 56 | Expecto.FsCheck (9.0.2) 57 | Expecto (>= 9.0.2) 58 | FsCheck (>= 2.14.2) 59 | FsCheck (2.14.3) 60 | FSharp.Core (>= 4.2.3) 61 | FSharp.Core (5.0) 62 | Iced (1.10) 63 | Microsoft.Bcl.AsyncInterfaces (5.0) 64 | System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net50) (>= net461)) (&& (== net50) (< netcoreapp2.1) (< netstandard2.1)) (&& (== netcoreapp3.1) (>= net461)) (&& (== netcoreapp3.1) (< netcoreapp2.1) (< netstandard2.1)) (== netstandard2.0) 65 | Microsoft.CodeAnalysis.Analyzers (3.3.2) 66 | Microsoft.CodeAnalysis.Common (3.8) 67 | Microsoft.CodeAnalysis.Analyzers (>= 3.0) 68 | System.Collections.Immutable (>= 5.0) 69 | System.Memory (>= 4.5.4) 70 | System.Reflection.Metadata (>= 5.0) 71 | System.Runtime.CompilerServices.Unsafe (>= 4.7.1) 72 | System.Text.Encoding.CodePages (>= 4.5.1) 73 | System.Threading.Tasks.Extensions (>= 4.5.4) 74 | Microsoft.CodeAnalysis.CSharp (3.8) 75 | Microsoft.CodeAnalysis.Common (3.8) 76 | Microsoft.Diagnostics.NETCore.Client (0.2.160202) 77 | Microsoft.Bcl.AsyncInterfaces (>= 1.1) 78 | Microsoft.Diagnostics.Runtime (2.0.156101) 79 | Microsoft.Diagnostics.NETCore.Client (>= 0.2.61701) 80 | System.Buffers (>= 4.5.1) 81 | System.Collections.Immutable (>= 1.7.1) 82 | System.Memory (>= 4.5.4) 83 | System.Reflection.Metadata (>= 1.8.1) 84 | System.Runtime.CompilerServices.Unsafe (>= 4.7.1) 85 | Microsoft.Diagnostics.Tracing.TraceEvent (2.0.62) 86 | System.Runtime.CompilerServices.Unsafe (>= 4.5.2) 87 | Microsoft.DotNet.PlatformAbstractions (3.1.6) 88 | Microsoft.NETCore.Platforms (5.0) - restriction: || (== net50) (== netcoreapp3.1) (&& (== netstandard2.0) (>= netcoreapp2.0)) 89 | Microsoft.Win32.Registry (5.0) 90 | System.Buffers (>= 4.5.1) - restriction: || (&& (== net50) (>= monotouch)) (&& (== net50) (< netcoreapp2.0)) (&& (== net50) (>= xamarinios)) (&& (== net50) (>= xamarinmac)) (&& (== net50) (>= xamarintvos)) (&& (== net50) (>= xamarinwatchos)) (&& (== netcoreapp3.1) (>= monotouch)) (&& (== netcoreapp3.1) (< netcoreapp2.0)) (&& (== netcoreapp3.1) (>= xamarinios)) (&& (== netcoreapp3.1) (>= xamarinmac)) (&& (== netcoreapp3.1) (>= xamarintvos)) (&& (== netcoreapp3.1) (>= xamarinwatchos)) (== netstandard2.0) 91 | System.Memory (>= 4.5.4) - restriction: || (&& (== net50) (< netcoreapp2.0)) (&& (== net50) (< netcoreapp2.1)) (&& (== net50) (>= uap10.1)) (&& (== netcoreapp3.1) (< netcoreapp2.0)) (&& (== netcoreapp3.1) (< netcoreapp2.1)) (&& (== netcoreapp3.1) (>= uap10.1)) (== netstandard2.0) 92 | System.Security.AccessControl (>= 5.0) 93 | System.Security.Principal.Windows (>= 5.0) 94 | Mono.Cecil (0.11.3) 95 | Perfolizer (0.2.1) 96 | System.Memory (>= 4.5.3) 97 | System.Buffers (4.5.1) 98 | System.CodeDom (5.0) 99 | System.Collections.Immutable (5.0) 100 | System.Memory (>= 4.5.4) - restriction: || (&& (== net50) (>= net461)) (&& (== net50) (< netcoreapp2.1)) (&& (== net50) (< netstandard2.0)) (&& (== net50) (>= uap10.1)) (&& (== netcoreapp3.1) (>= net461)) (&& (== netcoreapp3.1) (< netcoreapp2.1)) (&& (== netcoreapp3.1) (< netstandard2.0)) (&& (== netcoreapp3.1) (>= uap10.1)) (== netstandard2.0) 101 | System.Management (5.0) 102 | Microsoft.NETCore.Platforms (>= 5.0) - restriction: || (== net50) (== netcoreapp3.1) (&& (== netstandard2.0) (>= netcoreapp2.0)) 103 | Microsoft.Win32.Registry (>= 5.0) - restriction: || (== net50) (== netcoreapp3.1) (&& (== netstandard2.0) (>= netcoreapp2.0)) 104 | System.CodeDom (>= 5.0) 105 | System.Memory (4.5.4) 106 | System.Buffers (>= 4.5.1) - restriction: || (&& (== net50) (>= monotouch)) (&& (== net50) (>= net461)) (&& (== net50) (< netcoreapp2.0)) (&& (== net50) (< netstandard1.1)) (&& (== net50) (< netstandard2.0)) (&& (== net50) (>= xamarinios)) (&& (== net50) (>= xamarinmac)) (&& (== net50) (>= xamarintvos)) (&& (== net50) (>= xamarinwatchos)) (&& (== netcoreapp3.1) (>= monotouch)) (&& (== netcoreapp3.1) (>= net461)) (&& (== netcoreapp3.1) (< netcoreapp2.0)) (&& (== netcoreapp3.1) (< netstandard1.1)) (&& (== netcoreapp3.1) (< netstandard2.0)) (&& (== netcoreapp3.1) (>= xamarinios)) (&& (== netcoreapp3.1) (>= xamarinmac)) (&& (== netcoreapp3.1) (>= xamarintvos)) (&& (== netcoreapp3.1) (>= xamarinwatchos)) (== netstandard2.0) 107 | System.Numerics.Vectors (>= 4.4) - restriction: || (&& (== net50) (< netcoreapp2.0)) (&& (== netcoreapp3.1) (< netcoreapp2.0)) (== netstandard2.0) 108 | System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - restriction: || (&& (== net50) (>= monotouch)) (&& (== net50) (>= net461)) (&& (== net50) (< netcoreapp2.0)) (&& (== net50) (< netcoreapp2.1)) (&& (== net50) (< netstandard1.1)) (&& (== net50) (< netstandard2.0)) (&& (== net50) (>= uap10.1)) (&& (== net50) (>= xamarinios)) (&& (== net50) (>= xamarinmac)) (&& (== net50) (>= xamarintvos)) (&& (== net50) (>= xamarinwatchos)) (&& (== netcoreapp3.1) (>= monotouch)) (&& (== netcoreapp3.1) (>= net461)) (&& (== netcoreapp3.1) (< netcoreapp2.0)) (&& (== netcoreapp3.1) (< netcoreapp2.1)) (&& (== netcoreapp3.1) (< netstandard1.1)) (&& (== netcoreapp3.1) (< netstandard2.0)) (&& (== netcoreapp3.1) (>= uap10.1)) (&& (== netcoreapp3.1) (>= xamarinios)) (&& (== netcoreapp3.1) (>= xamarinmac)) (&& (== netcoreapp3.1) (>= xamarintvos)) (&& (== netcoreapp3.1) (>= xamarinwatchos)) (== netstandard2.0) 109 | System.Numerics.Vectors (4.5) - restriction: || (&& (== net50) (>= net461)) (&& (== net50) (< netcoreapp2.0)) (&& (== net50) (< netstandard2.0)) (&& (== net50) (>= uap10.1)) (&& (== netcoreapp3.1) (>= net461)) (&& (== netcoreapp3.1) (< netcoreapp2.0)) (&& (== netcoreapp3.1) (< netstandard2.0)) (&& (== netcoreapp3.1) (>= uap10.1)) (== netstandard2.0) 110 | System.Reflection.Emit (4.7) 111 | System.Reflection.Emit.ILGeneration (>= 4.7) - restriction: || (&& (== net50) (< netcoreapp2.0) (< netstandard2.1)) (&& (== net50) (< netstandard1.1)) (&& (== net50) (< netstandard2.0)) (&& (== net50) (>= uap10.1)) (&& (== netcoreapp3.1) (< netcoreapp2.0) (< netstandard2.1)) (&& (== netcoreapp3.1) (< netstandard1.1)) (&& (== netcoreapp3.1) (< netstandard2.0)) (&& (== netcoreapp3.1) (>= uap10.1)) (== netstandard2.0) 112 | System.Reflection.Emit.ILGeneration (4.7) - restriction: || (&& (== net50) (< netcoreapp2.0) (< netstandard2.1)) (&& (== net50) (< netstandard1.1)) (&& (== net50) (< netstandard2.0)) (&& (== net50) (>= uap10.1)) (&& (== netcoreapp3.1) (< netcoreapp2.0) (< netstandard2.1)) (&& (== netcoreapp3.1) (< netstandard1.1)) (&& (== netcoreapp3.1) (< netstandard2.0)) (&& (== netcoreapp3.1) (>= uap10.1)) (== netstandard2.0) 113 | System.Reflection.Emit.Lightweight (4.7) 114 | System.Reflection.Emit.ILGeneration (>= 4.7) - restriction: || (&& (== net50) (< netcoreapp2.0) (< netstandard2.1)) (&& (== net50) (< netstandard2.0)) (&& (== net50) (< portable-net45+wp8)) (&& (== net50) (>= uap10.1)) (&& (== netcoreapp3.1) (< netcoreapp2.0) (< netstandard2.1)) (&& (== netcoreapp3.1) (< netstandard2.0)) (&& (== netcoreapp3.1) (< portable-net45+wp8)) (&& (== netcoreapp3.1) (>= uap10.1)) (== netstandard2.0) 115 | System.Reflection.Metadata (5.0) 116 | System.Collections.Immutable (>= 5.0) - restriction: || (&& (== net50) (>= net461)) (&& (== net50) (< netstandard1.1)) (&& (== net50) (< netstandard2.0)) (== netcoreapp3.1) (== netstandard2.0) 117 | System.Runtime.CompilerServices.Unsafe (5.0) 118 | System.Security.AccessControl (5.0) 119 | Microsoft.NETCore.Platforms (>= 5.0) - restriction: || (== net50) (== netcoreapp3.1) (&& (== netstandard2.0) (>= netcoreapp2.0)) 120 | System.Security.Principal.Windows (>= 5.0) 121 | System.Security.Principal.Windows (5.0) 122 | System.Text.Encoding.CodePages (5.0) 123 | Microsoft.NETCore.Platforms (>= 5.0) - restriction: || (== net50) (== netcoreapp3.1) (&& (== netstandard2.0) (>= net50)) (&& (== netstandard2.0) (>= netcoreapp2.0)) 124 | System.Runtime.CompilerServices.Unsafe (>= 5.0) - restriction: || (&& (== net50) (>= net461)) (&& (== net50) (< netcoreapp2.0)) (== netcoreapp3.1) (== netstandard2.0) 125 | System.Threading.Tasks.Extensions (4.5.4) 126 | System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - restriction: || (&& (== net50) (>= net461)) (&& (== net50) (< netcoreapp2.1)) (&& (== net50) (< netstandard1.0)) (&& (== net50) (< netstandard2.0)) (&& (== net50) (>= wp8)) (&& (== netcoreapp3.1) (>= net461)) (&& (== netcoreapp3.1) (< netcoreapp2.1)) (&& (== netcoreapp3.1) (< netstandard1.0)) (&& (== netcoreapp3.1) (< netstandard2.0)) (&& (== netcoreapp3.1) (>= wp8)) (== netstandard2.0) 127 | System.ValueTuple (4.5) 128 | -------------------------------------------------------------------------------- /src/FSharpWrap.Tool/FSharpWrap.Tool.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | FSharpWrap.Tool 5 | Exe 6 | netcoreapp3.1 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/FSharpWrap.Tool/Filter.fs: -------------------------------------------------------------------------------- 1 | namespace FSharpWrap.Tool 2 | 3 | open System.Reflection 4 | 5 | type FilterType<'Item when 'Item : comparison> = 6 | | Exclude of Set<'Item> 7 | | Include of Set<'Item> 8 | | All 9 | 10 | member this.Items = 11 | match this with 12 | | Exclude items 13 | | Include items -> items 14 | | All -> Set.empty 15 | 16 | type Filter = 17 | { Assemblies: FilterType 18 | Namespaces: FilterType } 19 | 20 | static member Empty = 21 | { Assemblies = All 22 | Namespaces = All } 23 | 24 | [] 25 | module Filter = 26 | let private all _ = true 27 | 28 | let inline private included items map = 29 | let found items' item = 30 | let item' = map item 31 | Set.contains item' items' 32 | match items with 33 | | Exclude exc -> found exc >> not 34 | | Include inc -> found inc 35 | | All -> all 36 | 37 | let assemblyIncluded { Assemblies = assms } = 38 | fun (assm: Assembly) -> 39 | assm.GetName().Name 40 | |> included assms 41 | 42 | let typeIncluded { Namespaces = namespaces } = 43 | fun (t: System.Type) -> 44 | Namespace.ofStr t.Namespace 45 | |> included namespaces 46 | -------------------------------------------------------------------------------- /src/FSharpWrap.Tool/FsName.fs: -------------------------------------------------------------------------------- 1 | namespace FSharpWrap.Tool 2 | 3 | open System.Reflection 4 | 5 | [] 6 | type FsName = 7 | internal 8 | | FsName of string 9 | 10 | override this.ToString() = 11 | let (FsName name) = this in name 12 | 13 | [] 14 | module FsName = 15 | let ofStr = 16 | function 17 | | null | "" -> None 18 | | str -> FsName str |> Some 19 | 20 | let ofType (t: System.Type) = // TODO: Return option instead of throwing exception? 21 | match t.DeclaringType, MemberInfo.compiledName t with 22 | | _, "" 23 | | _, null -> invalidArg "t" "The name of the type was null or empty" 24 | | null, name when t.IsGenericType -> 25 | name.LastIndexOf '`' |> name.Remove 26 | | _, name -> name 27 | |> FsName 28 | 29 | let ofParameter (param: ParameterInfo) = 30 | ofStr param.Name |> Option.defaultValue (sprintf "_arg%i" param.Position |> FsName) 31 | -------------------------------------------------------------------------------- /src/FSharpWrap.Tool/Generation/Generate.fs: -------------------------------------------------------------------------------- 1 | [] 2 | module FSharpWrap.Tool.Generation.Generate 3 | 4 | open FSharpWrap.Tool 5 | open FSharpWrap.Tool.Reflection 6 | 7 | let private attrType ns name = 8 | { Name = FsName name 9 | Namespace = Namespace.ofStr ns 10 | Parent = None 11 | TypeArgs = TypeArgList.empty } 12 | 13 | let private moduleAttr = 14 | { Arguments = [ "global.Microsoft.FSharp.Core.CompilationRepresentationFlags.ModuleSuffix" ] 15 | AttributeType = attrType "Microsoft.FSharp.Core" "CompilationRepresentationAttribute" } 16 | 17 | let private ienumerable = 18 | { Name = FsName "IEnumerable" 19 | Namespace = Namespace.ofStr "System.Collections.Generic" 20 | Parent = None 21 | TypeArgs = 22 | { Constraints = GenericConstraints.Empty() 23 | ParamName = FsName "T" } 24 | |> TypeParam 25 | |> TypeArgList.singleton } 26 | 27 | // TODO: How will the arguments be casted to the argument type? 28 | let attribute (attr: AttributeInfo) = 29 | let rec arg (t, value) = 30 | match value with 31 | | AttributeArg.Array items -> 32 | List.map arg items 33 | |> String.concat ";" 34 | |> sprintf "[|%s|]" 35 | | AttributeArg.Bool b -> sprintf "%b" b 36 | | AttributeArg.String str -> String.toLiteral str 37 | | _ -> sprintf "/* Unknown argument %A */" value 38 | { Arguments = 39 | let namedArgs = 40 | attr.NamedArgs 41 | |> Map.toList 42 | |> List.map 43 | (fun (name, info) -> 44 | let name' = Print.fsname name 45 | arg info |> sprintf "%s=%s" name') 46 | List.append 47 | (List.map arg attr.ConstructorArgs) 48 | namedArgs 49 | AttributeType = attr.AttributeType } 50 | 51 | let private warnAttrs = 52 | let warnings = 53 | [ 54 | "System", "ObsoleteAttribute" 55 | "Microsoft.FSharp.Core", "ExperimentalAttribute" 56 | ] 57 | |> List.map (fun name -> name ||> attrType) 58 | |> Set.ofList 59 | fun (attrs: AttributeInfo list) -> 60 | List.filter 61 | (fun attr -> 62 | Set.contains 63 | attr.AttributeType 64 | warnings) 65 | attrs 66 | |> List.map attribute 67 | 68 | let binding parent (mber: Member) = 69 | let name = Print.memberName mber 70 | let name' = FsName name 71 | let temp = {| Attributes = warnAttrs mber.Attributes |} 72 | let this = 73 | { ArgType = TypeName parent.TypeName |> TypeArg 74 | IsOptional = RequiredParam 75 | ParamName = FsName "this" } 76 | match mber.Type with 77 | | Constructor ctor when name.StartsWith "of" -> 78 | let cparams = ParamList.ofList ctor 79 | // TODO: Factor out common code for generating functions. 80 | {| temp with 81 | Body = 82 | sprintf 83 | "new %s(%s)" 84 | (Print.typeName parent.TypeName) 85 | (Print.arguments cparams) 86 | Name = name' 87 | Parameters = cparams |} 88 | |> GenFunction 89 | |> Some 90 | | InstanceField ({ IsReadOnly = ReadOnly } as field) -> 91 | {| temp with 92 | Body = 93 | sprintf 94 | "%s.``%s``:%s" 95 | (Print.fsname this.ParamName) 96 | field.FieldName 97 | (Print.typeArg field.FieldType) 98 | Name = name' 99 | Parameters = ParamList.singleton this |} 100 | |> GenFunction 101 | |> Some 102 | | InstanceMethod mthd -> 103 | let mparams = ParamList.ofList mthd.Params 104 | let targs = 105 | match mthd.TypeArgs with 106 | | TypeArgs(_ :: _ as targs) -> 107 | List.map 108 | Print.typeArg 109 | targs 110 | |> String.concat "," 111 | |> sprintf "<%s>" 112 | | _ -> "" 113 | let mparams', (this', _) = ParamList.append this mparams 114 | {| temp with 115 | Body = 116 | sprintf 117 | "%s.``%s``%s(%s)" 118 | (Print.fsname this') 119 | mthd.MethodName 120 | targs 121 | (Print.arguments mparams) 122 | Name = name' 123 | Parameters = mparams' |} 124 | |> GenFunction 125 | |> Some 126 | | InstanceProperty ({ PropType = TypeArg(IsNamedType "System" "Boolean" _); Setter = false } as prop) -> 127 | {| temp with 128 | Body = 129 | sprintf 130 | "if %s.``%s`` then Some() else None" 131 | (Print.fsname this.ParamName) 132 | prop.PropName 133 | Parameters = ParamList.singleton this 134 | PatternName = FsName prop.PropName |} 135 | |> GenActivePattern 136 | |> Some 137 | | InstanceProperty ({ Setter = false } as prop) -> 138 | // TODO: Factor out common code shared with an InstanceField 139 | {| temp with 140 | Body = 141 | sprintf 142 | "%s.``%s``" 143 | (Print.fsname this.ParamName) 144 | prop.PropName 145 | Name = name' 146 | Parameters = ParamList.singleton this |} 147 | |> GenFunction 148 | |> Some 149 | // TODO: Create functions to call static methods, make sure to filter out union case constructors. 150 | | _ -> None 151 | 152 | let fromType (t: TypeDef): GenModule = 153 | let isRef = 154 | function 155 | | { Param.ArgType = TypeArg(ByRefType _) } -> true 156 | | _ -> false 157 | { Attributes = moduleAttr :: (warnAttrs t.Attributes) 158 | Bindings = 159 | /// Attempts to create a Computation Expression for the type 160 | let expr = 161 | if not t.IsAbstract && Set.contains ienumerable t.Interfaces 162 | then 163 | let tname = Print.typeName t.TypeName 164 | let t' = TypeName t.TypeName |> TypeArg 165 | let idt = FsFuncType(t', t') |> TypeArg 166 | let idtname = Print.typeArg idt 167 | let empty = 168 | List.tryPick 169 | (fun mber -> 170 | match mber.Type with 171 | | StaticField { FieldName = "Empty" } -> 172 | sprintf "%s.Empty" tname |> Some 173 | | Constructor [] -> 174 | sprintf "new %s()" tname |> Some 175 | | _ -> None) 176 | t.Members 177 | let ops = 178 | let ret (rt: TypeArg) = 179 | if rt = t' 180 | then System.String.Empty 181 | else " |> ignore; this" 182 | let others = 183 | List.collect 184 | (fun mber -> 185 | match mber.Type with 186 | | InstanceMethod({ MethodName = String.OneOf [ "Add"; "AddRange"; "Push"; "Enqueue" ]; Params = [ arg ] } as mthd) -> 187 | [ 188 | { From = mthd.MethodName = "AddRange" 189 | Item = arg.ArgType 190 | Yield = 191 | fun item -> 192 | ret mthd.RetType 193 | |> sprintf 194 | "fun (this: %s) -> this.%s(%s)%s" 195 | tname 196 | mthd.MethodName 197 | item } 198 | |> Yield 199 | ] 200 | | InstanceMethod({ MethodName = "Add"; Params = [ _; _ ] } as mthd) -> 201 | [ 202 | { From = false 203 | Item = TypeArg InferredType 204 | Yield = 205 | fun item -> 206 | ret mthd.RetType 207 | |> sprintf 208 | "fun (this: %s) -> this.%s(fst %s, snd %s)%s" 209 | tname 210 | mthd.MethodName 211 | item 212 | item } 213 | |> Yield 214 | ] 215 | | _ -> List.empty) 216 | t.Members 217 | [ 218 | { Combine = sprintf "%s >> %s" 219 | One = idt 220 | Two = idt } 221 | |> Combine 222 | 223 | sprintf 224 | "For(items: seq<_>, body): %s = fun this -> Seq.fold (fun state item -> body item state) this items" 225 | idtname 226 | |> Custom 227 | 228 | sprintf 229 | "TryFinally(body: %s, fin: unit -> unit) = fun this -> try body this finally fin()" 230 | idtname 231 | |> Custom 232 | 233 | { Type = idt 234 | Using = 235 | sprintf 236 | "fun (this: %s) -> this |> using %s %s" 237 | tname } 238 | |> Using 239 | 240 | Delay idt 241 | Zero t' 242 | 243 | if empty.IsSome then Run(idt, empty.Value) 244 | 245 | yield! others 246 | ] 247 | |> Set.ofList 248 | {| Attributes = List.empty 249 | Name = 250 | let (FsName name) = t.TypeName.Name 251 | sprintf "%sBuilder" name |> FsName 252 | Operations = ops |} 253 | |> GenBuilder 254 | |> Set.add 255 | else id 256 | t.Members 257 | |> List.choose 258 | (fun mber -> 259 | match mber.Type with 260 | | Constructor plist 261 | | InstanceMethod { Params = plist } 262 | | StaticMethod { Params = plist } when List.exists isRef plist -> 263 | None 264 | | _ -> Some mber) 265 | |> List.fold 266 | (fun bindings mber -> 267 | match binding t mber with 268 | | Some gen when Set.contains gen bindings |> not -> 269 | Set.add gen bindings 270 | | _ -> bindings) 271 | Set.empty 272 | |> expr 273 | ModuleName = t.TypeName.Name } 274 | 275 | let private addType mdles tdef = 276 | let { Name = name; Namespace = ns } = tdef.TypeName 277 | let types = 278 | mdles 279 | |> Map.tryFind ns 280 | |> Option.defaultValue Map.empty 281 | let mdle = 282 | let init = fromType tdef 283 | match Map.tryFind name types with 284 | | Some existing -> 285 | let bindings = 286 | Set.union 287 | existing.Bindings 288 | init.Bindings 289 | { existing with Bindings = bindings } 290 | | None -> init 291 | match mdle.Bindings with 292 | | Empty -> mdles 293 | | _ -> 294 | let types' = 295 | Map.add 296 | name 297 | mdle 298 | types 299 | Map.add ns types' mdles 300 | 301 | let fromAssemblies (assms: seq) = 302 | { Header = 303 | seq { 304 | "This code was automatically generated by FSharpWrap" 305 | "Changes made to this file will be lost when it is regenerated" 306 | for assm in assms do 307 | sprintf "- %s" assm.FullName 308 | } 309 | IgnoredWarnings = [ 44u; 57u; 64u; ] 310 | Namespaces = 311 | assms 312 | |> Seq.collect (fun assm -> assm.Types) 313 | |> Seq.fold 314 | addType 315 | Map.empty } 316 | -------------------------------------------------------------------------------- /src/FSharpWrap.Tool/Generation/ParamList.fs: -------------------------------------------------------------------------------- 1 | namespace FSharpWrap.Tool.Generation 2 | 3 | open System.Collections 4 | open System.Collections.Generic 5 | open System.ComponentModel 6 | 7 | open FSharpWrap.Tool 8 | open FSharpWrap.Tool.Reflection 9 | 10 | type GenParam = FsName * Param 11 | 12 | [] 13 | module ParamList = 14 | [] 15 | type ParamList = 16 | private 17 | | ParamList of GenParam list * Set 18 | 19 | member private this.Items = 20 | let (ParamList(plist, _)) = this in plist 21 | interface IEnumerable with 22 | member this.GetEnumerator() = (this.Items :> IEnumerable<_>).GetEnumerator() 23 | interface IEnumerable with 24 | member this.GetEnumerator() = (this.Items :> IEnumerable).GetEnumerator() 25 | 26 | let private safe set { Param.ParamName = FsName name } = 27 | let lname = String.toCamelCase name |> FsName 28 | let sname = 29 | if Set.contains lname set 30 | then sprintf "%O'" lname |> FsName 31 | else lname 32 | sname, Set.add sname set 33 | 34 | let empty = ParamList([], Set.empty) 35 | 36 | let singleton ({ Param.ParamName = name } as param) = 37 | ParamList([ name, param ], Set.singleton name) 38 | 39 | let append param (ParamList(list, set)) = 40 | let name, set' = safe set param 41 | let param' = name, param 42 | ParamList(list @ [ param' ], set'), param' 43 | 44 | let toList (ParamList(list, _)) = list 45 | 46 | let ofList = 47 | let rec inner set list = 48 | function 49 | | [] -> ParamList(List.rev list, set) 50 | | (h: Param) :: tail -> 51 | let name, set' = safe set h 52 | let list' = (name, h) :: list 53 | inner set' list' tail 54 | inner Set.empty [] 55 | 56 | type ParamList = ParamList.ParamList 57 | 58 | [] 59 | module ParamListPatterns = 60 | let (|EmptyParams|ParamList|) plist = 61 | match ParamList.toList plist with 62 | | [] -> Choice1Of2() 63 | | plist' -> Choice2Of2 plist' 64 | -------------------------------------------------------------------------------- /src/FSharpWrap.Tool/Generation/Print.fs: -------------------------------------------------------------------------------- 1 | [] 2 | module rec FSharpWrap.Tool.Generation.Print 3 | 4 | open System 5 | open System.IO 6 | 7 | open FSharpWrap.Tool 8 | open FSharpWrap.Tool.Reflection 9 | 10 | let private indented out = 11 | let mutable indented = false 12 | { out with 13 | Write = 14 | fun str -> 15 | if not indented then 16 | indented <- true 17 | out.Write " " 18 | out.Write str 19 | Line = 20 | fun() -> 21 | indented <- false 22 | out.Line() } 23 | 24 | let fsname (FsName name) = sprintf "``%s``" name 25 | 26 | let ns (Namespace strs) = 27 | match strs with 28 | | [] -> "global" 29 | | _ -> 30 | strs 31 | |> List.map fsname 32 | |> String.concat "." 33 | 34 | let typeArg = 35 | function 36 | | TypeArg targ -> typeRef targ 37 | | TypeParam tparam -> fsname tparam.ParamName |> sprintf "'%s" 38 | 39 | let paramType { Param.ArgType = argt } = 40 | match argt with 41 | | TypeArg targ -> typeRef targ 42 | | TypeParam tparam -> 43 | let tname = fsname tparam.ParamName |> sprintf "'%s" 44 | match tparam with 45 | | HasGenericConstraints constraints -> 46 | Seq.map 47 | (fun constr -> 48 | let (TypeConstraint derives) = constr 49 | typeArg derives |> sprintf "%s:>%s" tname) 50 | constraints 51 | |> String.concat " and " 52 | |> sprintf " when %s" 53 | | _ -> "" 54 | |> sprintf "%s%s" tname 55 | 56 | let typeRef = 57 | function 58 | | ArrayType arr -> 59 | let rank = 60 | match arr.Rank with 61 | | 0u | 1u -> "" 62 | | _ -> String(',', arr.Rank - 1u |> int) 63 | sprintf 64 | "%s[%s]" 65 | (typeArg arr.ElementType) 66 | rank 67 | | ByRefType tref -> 68 | typeArg tref |> sprintf "%s ref" 69 | | FsFuncType(param, ret) -> 70 | sprintf 71 | "(%s -> %s)" 72 | (typeArg param) 73 | (typeArg ret) 74 | | InferredType -> "_" 75 | | PointerType (TypeArg (IsNamedType "System" "Void" _)) -> "voidptr" 76 | | PointerType pnt -> 77 | typeArg pnt |> sprintf "nativeptr<%s>" 78 | | TypeName tname -> typeName tname 79 | 80 | let typeName { Name = name; Namespace = nspace; Parent = parent; TypeArgs = TypeArgs targs } = 81 | let name' = 82 | let targs' = 83 | match targs with 84 | | [] -> "" 85 | | _ -> 86 | List.map typeArg targs 87 | |> String.concat "," 88 | |> sprintf "<%s>" 89 | sprintf 90 | "%s%s" 91 | (fsname name) 92 | targs' 93 | match parent with 94 | | None -> 95 | sprintf "%s.%s" (ns nspace) 96 | | Some parent' -> 97 | sprintf "%s.%s" (typeName parent') 98 | <| name' 99 | 100 | // TODO: How will generic methods and static fields of generic types be handled, maybe add []? 101 | let memberName mber = 102 | match mber.Type with 103 | | Constructor cparams -> 104 | let ptypes = 105 | List.map 106 | (fun pt -> 107 | match pt.ArgType with 108 | | TypeArg targ -> Some targ 109 | | _ -> None) 110 | cparams 111 | match ptypes with 112 | | [ Some (IsNamedType "System.Collections.Generic" "IEnumerable" _ & TypeName { TypeArgs = TypeArgs [ _ ] }) ] -> 113 | "ofSeq" 114 | | [ Some (IsNamedType "Microsoft.FSharp.Collections" "List" _ & TypeName { TypeArgs = TypeArgs [ _ ] }) ] -> 115 | "ofList" 116 | | [ Some (ArrayType _) ] -> 117 | "ofArray" 118 | | [ Some (TypeName { Name = pname }) ] -> sprintf "of%O" pname 119 | | _ -> "create" 120 | | InstanceField field 121 | | StaticField field -> field.FieldName 122 | | InstanceMethod mthd 123 | | StaticMethod mthd -> mthd.MethodName 124 | | InstanceProperty prop 125 | | StaticProperty prop -> prop.PropName 126 | | UnknownMember name -> name 127 | |> String.toCamelCase 128 | 129 | let arguments parameters = 130 | Seq.map 131 | (fun (pname, param) -> 132 | let name = fsname param.ParamName 133 | let f = 134 | match param.IsOptional with 135 | | FsOptionalParam -> sprintf "?%s=%s" 136 | | OptionalParam -> sprintf "%s=%s" 137 | | RequiredParam -> fun _ -> id 138 | fsname pname |> f name) 139 | parameters 140 | |> String.concat "," 141 | 142 | let attributes out (attrs: seq) = 143 | Seq.iter 144 | (fun (attr: GenAttribute) -> 145 | out.Write "[<" 146 | typeName attr.AttributeType |> out.Write 147 | out.Write "(" 148 | String.concat "," attr.Arguments |> out.Write 149 | out.Write ")>]" 150 | out.Line()) 151 | attrs 152 | 153 | let parameters = 154 | function 155 | | EmptyParams -> "()" 156 | | ParamList plist -> 157 | List.map 158 | (fun (pname, param) -> 159 | sprintf 160 | "(%s:%s)" 161 | (Print.fsname pname) 162 | (paramType param)) 163 | plist 164 | |> String.Concat 165 | 166 | let genBinding out (binding: GenBinding) = 167 | attributes out binding.Attributes 168 | match binding with 169 | | GenActivePattern pattern -> 170 | out.Write "let inline " 171 | sprintf 172 | "(|%s|_|)%s= %s" 173 | (fsname pattern.PatternName) 174 | (parameters pattern.Parameters) 175 | pattern.Body 176 | |> out.Write 177 | out.Line() 178 | | GenBuilder ce -> 179 | let name' = fsname ce.Name 180 | out.Write "type " 181 | out.Write name' 182 | out.Write "()=" 183 | out.Line() 184 | let out' = indented out 185 | for op in ce.Operations do 186 | out'.Write "member inline _." 187 | match op with 188 | | Combine combine -> 189 | out'.Write "Combine(one:" 190 | typeArg combine.One |> out'.Write 191 | out'.Write ",two:" 192 | typeArg combine.Two |> out'.Write 193 | out'.Write ")=" 194 | combine.Combine "one" "two" |> out'.Write 195 | | Delay ret -> 196 | out'.Write "Delay(f): " 197 | typeArg ret |> out'.Write 198 | out'.Write " =f()" 199 | | Run(t, empty) -> 200 | out'.Write "Run(f:" 201 | typeArg t |> out'.Write 202 | out'.Write ")=f (" 203 | out'.Write empty 204 | out'.Write ")" 205 | | Using u -> 206 | out'.Write "Using(resource,body: _ -> " 207 | typeArg u.Type |> out'.Write 208 | out'.Write ")= " 209 | u.Using "resource" "body" |> out'.Write 210 | | Yield yld -> 211 | out'.Write "Yield" 212 | if yld.From then out'.Write "From" 213 | out'.Write "(item:" 214 | typeArg yld.Item |> out'.Write 215 | out'.Write ")= " 216 | yld.Yield "item" |> out'.Write 217 | | Zero t -> 218 | out'.Write "Zero(): _ -> " 219 | typeArg t |> out'.Write 220 | out'.Write " =id" 221 | | Custom str -> 222 | out'.Write str 223 | out'.Line() 224 | out.Write "let expr = new " 225 | out.Write name' 226 | out.Write "()" 227 | out.Line() 228 | | GenFunction func -> 229 | out.Write "let inline " 230 | fsname func.Name |> out.Write 231 | parameters func.Parameters |> out.Write 232 | out.Write "= " 233 | out.Write func.Body 234 | out.Line() 235 | 236 | let genModule out (mdle: GenModule) = 237 | attributes out mdle.Attributes 238 | out.Write "module internal " 239 | fsname mdle.ModuleName |> out.Write 240 | out.Write " =" 241 | out.Line() 242 | let out' = indented out 243 | out'.Write "begin" 244 | out'.Line() 245 | Set.iter 246 | (indented out' |> genBinding) 247 | mdle.Bindings 248 | out'.Write "end" 249 | out'.Line() 250 | 251 | let genFile (file: GenFile) out = 252 | for line in file.Header do 253 | out.Write "// " 254 | out.Write line 255 | out.Line() 256 | 257 | if List.isEmpty file.IgnoredWarnings |> not then 258 | out.Write "#nowarn" 259 | for warn in file.IgnoredWarnings do 260 | sprintf " \"%i\"" warn |> out.Write 261 | out.Line() 262 | 263 | Map.iter 264 | (fun ns mdles -> 265 | out.Write "namespace " 266 | Print.ns ns |> out.Write 267 | out.Line() 268 | 269 | Map.iter 270 | (fun _ -> indented out |> genModule) 271 | mdles) 272 | file.Namespaces 273 | -------------------------------------------------------------------------------- /src/FSharpWrap.Tool/Generation/Types.fs: -------------------------------------------------------------------------------- 1 | namespace FSharpWrap.Tool.Generation 2 | 3 | open System 4 | 5 | open FSharpWrap.Tool 6 | open FSharpWrap.Tool.Reflection 7 | 8 | // TODO: Should AttributeInfo be used instead? 9 | type GenAttribute = 10 | { Arguments: string list 11 | AttributeType: TypeName } 12 | 13 | [] 14 | type ExprCombine = 15 | { Combine: string -> string -> string 16 | One: TypeArg 17 | Two: TypeArg } 18 | 19 | override this.Equals obj = 20 | let other = obj :?> ExprCombine 21 | this.One = other.One && this.Two = other.Two 22 | 23 | override this.GetHashCode() = hash(this.One, this.Two) 24 | 25 | interface IComparable with 26 | member this.CompareTo obj = 27 | let other = obj :?> ExprCombine 28 | compare (this.One, this.Two) (other.One, other.Two) 29 | 30 | [] 31 | type ExprYield = 32 | { From: bool 33 | Item: TypeArg 34 | Yield: string -> string } 35 | 36 | override this.Equals obj = this.Item = (obj :?> ExprYield).Item 37 | override this.GetHashCode() = this.Item.GetHashCode() 38 | 39 | interface IComparable with 40 | member this.CompareTo obj = compare this.Item (obj :?> ExprYield).Item 41 | 42 | [] 43 | type ExprUsing = 44 | { Type: TypeArg 45 | Using: string -> string -> string } 46 | 47 | override this.Equals obj = this.Type = (obj :?> ExprUsing).Type 48 | override this.GetHashCode() = this.Type.GetHashCode() 49 | 50 | interface IComparable with 51 | member this.CompareTo obj = compare this.Type (obj :?> ExprUsing).Type 52 | 53 | [] 54 | type ExprOperation = 55 | | Combine of ExprCombine 56 | | Custom of string 57 | | Delay of TypeArg 58 | | Run of TypeArg * string 59 | | Using of ExprUsing 60 | | Yield of ExprYield 61 | | Zero of TypeArg 62 | 63 | [] 64 | type GenBinding = 65 | | GenActivePattern of 66 | {| Attributes: GenAttribute list 67 | Body: string 68 | Parameters: ParamList 69 | PatternName: FsName |} 70 | /// Represents a computation expression type 71 | | GenBuilder of 72 | {| Attributes: GenAttribute list 73 | Name: FsName 74 | Operations: Set |} 75 | | GenFunction of 76 | {| Attributes: GenAttribute list 77 | Body: string 78 | Name: FsName 79 | Parameters: ParamList |} 80 | 81 | member this.Attributes = 82 | match this with 83 | | GenActivePattern pattern -> pattern.Attributes 84 | | GenBuilder ce -> ce.Attributes 85 | | GenFunction func -> func.Attributes 86 | 87 | override this.Equals obj = // TODO: How to ensure that there is no conflict between name of CE and a function? 88 | match this, obj :?> GenBinding with 89 | | GenFunction this, GenFunction other -> 90 | this.Name = other.Name 91 | | GenActivePattern this, GenActivePattern other -> 92 | this.PatternName = other.PatternName 93 | | GenBuilder this, GenBuilder other -> 94 | this.Name = other.Name 95 | | _ -> false 96 | override this.GetHashCode() = 97 | match this with 98 | | GenActivePattern pattern -> Choice1Of3 pattern.PatternName 99 | | GenBuilder ce -> Choice2Of3 ce.Name 100 | | GenFunction func -> Choice2Of3 func.Name 101 | |> hash 102 | 103 | interface IComparable with 104 | member this.CompareTo obj = 105 | match this, obj :?> GenBinding with 106 | | GenFunction this, GenFunction other -> 107 | compare this.Name other.Name 108 | | GenActivePattern this, GenActivePattern other -> 109 | compare this.PatternName other.PatternName 110 | | GenBuilder this, GenBuilder other -> 111 | compare this.Name other.Name 112 | | GenActivePattern _, _ 113 | | _, GenBuilder _ -> -1 114 | | _, GenActivePattern _ 115 | | GenBuilder _, _ -> 1 116 | 117 | [] 118 | type GenModule = 119 | { Attributes: GenAttribute list 120 | Bindings: Set 121 | ModuleName: FsName } 122 | 123 | override this.Equals obj = this.ModuleName = (obj :?> GenModule).ModuleName 124 | override this.GetHashCode() = this.ModuleName.GetHashCode() 125 | 126 | interface IComparable with 127 | member this.CompareTo obj = compare this.ModuleName (obj :?> GenModule).ModuleName 128 | 129 | type GenNamespace = Map 130 | 131 | type GenFile = 132 | { Header: seq 133 | IgnoredWarnings: uint list 134 | Namespaces: Map } 135 | 136 | [] 137 | type Printer = 138 | { Close: unit -> unit 139 | Line: unit -> unit 140 | Write: string -> unit } 141 | 142 | interface IDisposable with member this.Dispose() = this.Close() 143 | -------------------------------------------------------------------------------- /src/FSharpWrap.Tool/Namespace.fs: -------------------------------------------------------------------------------- 1 | namespace FSharpWrap.Tool 2 | 3 | [] 4 | type Namespace = 5 | | Namespace of FsName list 6 | 7 | override this.ToString() = 8 | let (Namespace ns) = this 9 | ns 10 | |> List.map (sprintf "%O") 11 | |> String.concat "." 12 | 13 | [] 14 | module Namespace = 15 | let ofStr = 16 | function 17 | | "" -> [] 18 | | str -> 19 | str.Split '.' 20 | |> List.ofArray 21 | |> List.choose FsName.ofStr 22 | >> Namespace 23 | -------------------------------------------------------------------------------- /src/FSharpWrap.Tool/Options.fs: -------------------------------------------------------------------------------- 1 | namespace FSharpWrap.Tool 2 | 3 | type Options = 4 | { AssemblyPaths: Path * Path list 5 | Filter: Filter 6 | LaunchDebugger: bool 7 | OutputFile: File } 8 | 9 | member this.Assemblies = 10 | let h, tail = this.AssemblyPaths in h :: tail 11 | 12 | type InvalidOptions = 13 | | EmptyAssemblyPaths 14 | | InvalidAssemblyPath of string 15 | | InvalidOutputFile of string 16 | | MixedFilter 17 | | MultipleOutputFiles 18 | | NoOutputFile 19 | | ShowUsage 20 | | InvalidArgument of string 21 | | InvalidOption of string 22 | 23 | override this.ToString() = 24 | match this with 25 | | ShowUsage -> "" 26 | | EmptyAssemblyPaths -> "Please specify the assemblies to generate code for" 27 | | InvalidAssemblyPath path -> sprintf "The path to the assembly '%s' is invalid" path 28 | | InvalidOutputFile file -> sprintf "The path to the output file is invalid '%s'" file 29 | | MixedFilter -> "Cannot both include in and exclude from in code generation" 30 | | MultipleOutputFiles -> "Please specify only one output file" 31 | | NoOutputFile -> "Please specify the path to the output file" 32 | | InvalidArgument arg -> sprintf "Invalid argument '%s'" arg 33 | | InvalidOption opt -> sprintf "Invalid option specified '--%s'" opt 34 | 35 | [] 36 | module Options = 37 | type StateType = 38 | private 39 | | AssemblyPaths 40 | | FilterAssemblyNames of (Set -> FilterType) 41 | | FilterNamespaces of (Set -> FilterType) 42 | | Invalid of InvalidOptions 43 | | LaunchDebugger 44 | | OutputFile 45 | | Unknown 46 | 47 | type private State = 48 | { AssemblyPaths: Path list 49 | Filter: Filter 50 | LaunchDebugger: bool 51 | OutputFile: File option 52 | Type: StateType } 53 | 54 | type OptionType = 55 | | Switch 56 | | Argument of string 57 | | ArgumentList of string 58 | 59 | type Info = 60 | { ArgType: OptionType 61 | Description: string 62 | State: StateType } 63 | 64 | let all = 65 | // TODO: Make some options accept directories and wildcards as well. 66 | [ 67 | "exclude-assembly-names", FilterAssemblyNames Exclude, "Specifies the names of the assembly files to exclude from code generation", ArgumentList "names" 68 | "exclude-namespaces", FilterNamespaces Exclude, "Specifies the namespaces of the types to exclude from code generation", ArgumentList "namespaces" 69 | "help", Invalid ShowUsage, "Shows this help message", Switch 70 | "include-assembly-names", FilterAssemblyNames Include, "Specifies the names of the assembly files to include in code generation", ArgumentList "names" 71 | "include-namespaces", FilterNamespaces Include, "Specifies the namespaces of the types to include in code generation", ArgumentList "namespaces" 72 | "launch-debugger", LaunchDebugger, "Calls Debugger.Launch after all arguments have been processed", Switch 73 | "output-file", OutputFile, "Specifies the path to the file containing the generated F# code", Argument "file" 74 | ] 75 | |> Seq.map (fun (name, st, desc, argt) -> 76 | name, 77 | { ArgType = argt 78 | Description = desc 79 | State = st }) 80 | |> Map.ofSeq 81 | 82 | let parse = 83 | let (|ValidOption|InvalidOption|Argument|) = 84 | function 85 | | (opt: string) when opt.StartsWith "--" -> 86 | let name = 87 | opt 88 | .Substring(2) 89 | .TrimEnd() 90 | match Map.tryFind name all with 91 | | Some opt' -> Choice1Of3 opt' 92 | | None -> Choice2Of3 name 93 | | arg -> Choice3Of3 arg 94 | let rec inner state args = 95 | match state, args with 96 | | { Type = Invalid msg }, _ -> 97 | Error msg 98 | | { Type = OutputFile; OutputFile = Some _ }, _ -> 99 | Error MultipleOutputFiles 100 | | { Type = LaunchDebugger }, _ -> 101 | let state' = { state with LaunchDebugger = true; Type = Unknown } 102 | inner state' args 103 | | _, [] -> 104 | match state with 105 | | { AssemblyPaths = phead :: ptail 106 | OutputFile = out } -> 107 | let out' = 108 | match out with 109 | | Some file -> file 110 | | None -> File.ofStr "output.autogen.fs" |> Option.get 111 | { AssemblyPaths = phead, ptail 112 | Filter = state.Filter 113 | LaunchDebugger = state.LaunchDebugger 114 | OutputFile = out' } 115 | |> Ok 116 | | { AssemblyPaths = [] } -> Error EmptyAssemblyPaths 117 | | _, arg :: tail -> 118 | let inline invalid err = { state with Type = Invalid err } 119 | let inline filter item (existing: FilterType<_>) f update = 120 | let items = 121 | Set.add item existing.Items |> f 122 | match existing, items with 123 | | Exclude _, Include _ 124 | | Include _, Exclude _ -> 125 | invalid MixedFilter 126 | | _ -> 127 | { state with Filter = update items state.Filter } 128 | let state' = 129 | match arg, state.Type with 130 | | (ValidOption arg', _) -> { state with Type = arg'.State } 131 | | (InvalidOption opt, _) -> InvalidOption opt |> invalid 132 | | (Path.Valid path, AssemblyPaths) -> 133 | { state with AssemblyPaths = path :: state.AssemblyPaths } 134 | | (File.Valid file, OutputFile) -> 135 | { state with OutputFile = Some file; Type = Unknown } 136 | | (name, FilterAssemblyNames t) -> 137 | filter 138 | name 139 | state.Filter.Assemblies 140 | t 141 | (fun names f -> { f with Assemblies = names }) 142 | | (ns, FilterNamespaces t) -> 143 | filter 144 | (Namespace.ofStr ns) 145 | state.Filter.Namespaces 146 | t 147 | (fun names f -> { f with Namespaces = names }) 148 | | (path, AssemblyPaths) -> InvalidAssemblyPath path |> invalid 149 | | (path, OutputFile) -> InvalidOutputFile path |> invalid 150 | | _ -> InvalidArgument arg |> invalid 151 | inner state' tail 152 | inner 153 | { AssemblyPaths = [] 154 | Filter = Filter.Empty 155 | LaunchDebugger = false 156 | OutputFile = None 157 | Type = AssemblyPaths } 158 | -------------------------------------------------------------------------------- /src/FSharpWrap.Tool/Path.fs: -------------------------------------------------------------------------------- 1 | namespace rec FSharpWrap.Tool 2 | 3 | open System 4 | open System.IO 5 | 6 | [] 7 | type Directory = 8 | { Path: string } 9 | 10 | override this.ToString() = this.Path 11 | 12 | [] 13 | type File = 14 | { Extension: string 15 | Name: string 16 | Parent: Directory 17 | Path: string } 18 | 19 | override this.ToString() = this.Path 20 | 21 | type Path = 22 | | File of File 23 | | Directory of Directory 24 | 25 | override this.ToString() = 26 | match this with 27 | | File { Path = path } 28 | | Directory { Path = path } -> path 29 | 30 | [] 31 | module File = 32 | let ofStr = 33 | function 34 | | "" 35 | | null -> None 36 | | str -> 37 | if Path.EndsInDirectorySeparator str 38 | then None 39 | else 40 | try 41 | let dir = 42 | str 43 | |> Path.GetDirectoryName 44 | |> Directory.ofStr 45 | |> Option.defaultWith 46 | (fun() -> sprintf "The directory for the file '%s' could not be parsed" str |> invalidOp) 47 | { File.Extension = Path.GetExtension str 48 | File.Name = Path.GetFileName str 49 | File.Parent = dir 50 | File.Path = str } 51 | |> Some 52 | with 53 | | :? ArgumentException 54 | | :? NotSupportedException 55 | | :? PathTooLongException -> None 56 | 57 | let (|Valid|Invalid|) str = 58 | match ofStr str with 59 | | Some file -> Choice1Of2 file 60 | | None -> Choice2Of2() 61 | 62 | let fullPath (file: File) = { file with File.Path = Path.GetFullPath file.Path } 63 | 64 | [] 65 | module Directory = 66 | let ofStr str = 67 | try 68 | let name = 69 | match str with 70 | | "" 71 | | null -> None 72 | | _ -> 73 | sprintf "%s/" str 74 | |> Path.GetDirectoryName 75 | |> Option.ofObj 76 | |> Option.defaultValue String.Empty 77 | Some { Directory.Path = name } 78 | with 79 | | :? ArgumentException 80 | | :? PathTooLongException -> None 81 | 82 | let (|Valid|Invalid|) str = 83 | match ofStr str with 84 | | Some file -> Choice1Of2 file 85 | | None -> Choice2Of2() 86 | 87 | let fullPath (dir: Directory) = { dir with Directory.Path = Path.GetFullPath dir.Path } 88 | 89 | [] 90 | module Path = 91 | let ofStr = 92 | function 93 | | File.Valid file -> File file |> Some 94 | | Directory.Valid dir -> Directory dir |> Some 95 | | _ -> None 96 | 97 | let (|Valid|Invalid|) str = 98 | match ofStr str with 99 | | Some path -> Choice1Of2 path 100 | | None -> Choice2Of2() 101 | 102 | let fullPath = 103 | function 104 | | File file -> File.fullPath file |> File 105 | | Directory dir -> Directory.fullPath dir |> Directory 106 | -------------------------------------------------------------------------------- /src/FSharpWrap.Tool/Program.fs: -------------------------------------------------------------------------------- 1 | [] 2 | module FSharpWrap.Tool.Program 3 | 4 | open System.Diagnostics 5 | open System.IO 6 | 7 | open FSharpWrap.Tool.Reflection 8 | open FSharpWrap.Tool.Generation 9 | 10 | [] 11 | let main argv = 12 | match List.ofArray argv |> Options.parse with 13 | | Ok args -> 14 | if args.LaunchDebugger then 15 | Debugger.Launch() |> ignore 16 | 17 | try 18 | let file = 19 | let name = File.fullPath args.OutputFile 20 | new StreamWriter(name.Path) 21 | let print = 22 | let assms = 23 | List.map Path.fullPath args.Assemblies 24 | args.Filter 25 | |> Reflect.paths assms 26 | |> Generate.fromAssemblies 27 | |> Print.genFile 28 | using 29 | file 30 | (fun stream -> 31 | { Close = stream.Close 32 | Line = stream.WriteLine 33 | Write = stream.Write } 34 | |> print) 35 | 0 36 | with 37 | | ex -> 38 | stderr.WriteLine ex.Message 39 | -1 40 | | Error ShowUsage -> 41 | printfn "Usage: fsharpwrap [options]" 42 | stdout.WriteLine() 43 | printfn "Assembly Files:" 44 | printfn " The paths to all assemblies and their dependencies" 45 | stdout.WriteLine() 46 | printfn "Options:" 47 | for name, opt in Map.toSeq Options.all do 48 | printf " --%s" name 49 | let arg = 50 | match opt.ArgType with 51 | | Options.Switch -> "" 52 | | Options.Argument name -> sprintf " <%s>" name 53 | | Options.ArgumentList names -> 54 | sprintf " [%s]" names 55 | printfn "%s" arg 56 | printfn " %s" opt.Description 57 | 0 58 | | Error msg -> 59 | stderr.WriteLine msg 60 | -1 61 | -------------------------------------------------------------------------------- /src/FSharpWrap.Tool/Reflection/Context.fs: -------------------------------------------------------------------------------- 1 | namespace FSharpWrap.Tool.Reflection 2 | 3 | open System 4 | open System.Collections.Generic 5 | 6 | open FSharpWrap.Tool 7 | 8 | [] 9 | type Context = 10 | private 11 | { Excluded: Filter 12 | TypeParams: Dictionary 13 | TypeRefs: Dictionary } 14 | 15 | member this.Filter = this.Excluded 16 | 17 | [] 18 | module internal ContextPatterns = 19 | let (|HasType|_|) (t: Type, ctx) = 20 | match t, ctx with 21 | | GenericParam _, { TypeParams = ContainsValue t tparam } -> 22 | TypeParam tparam |> Some 23 | | GenericArg, { TypeRefs = ContainsValue t tref } -> 24 | TypeArg tref |> Some 25 | | _ -> None 26 | 27 | [] 28 | module Context = 29 | let init filter = 30 | { Excluded = filter 31 | TypeParams = Dictionary<_, _>() 32 | TypeRefs = Dictionary<_, _>() } 33 | -------------------------------------------------------------------------------- /src/FSharpWrap.Tool/Reflection/MemberPatterns.fs: -------------------------------------------------------------------------------- 1 | [] 2 | module private FSharpWrap.Tool.Reflection.MemberPatterns 3 | 4 | open System 5 | open System.Reflection 6 | 7 | open FSharpWrap.Tool 8 | 9 | let (|GenericParam|GenericArg|) (t: Type) = 10 | if t.IsGenericParameter 11 | then t.GetGenericParameterConstraints() |> Choice1Of2 12 | else Choice2Of2() 13 | 14 | let (|GenericArgs|) (t: Type) = t.GetGenericArguments() 15 | 16 | let (|IsArray|_|) (t: Type) = 17 | if t.IsArray then t.GetElementType() |> Some else None 18 | 19 | let (|IsByRef|_|) (t: Type) = 20 | if t.IsByRef then t.GetElementType() |> Some else None 21 | 22 | let (|IsCompilerGenerated|_|): MemberInfo -> _ = 23 | MemberInfo.findAttr 24 | "System.Runtime.CompilerServices" 25 | "CompilerGeneratedAttribute" 26 | (fun _ -> Some ()) 27 | 28 | let (|IsNested|_|) (t: Type) = if t.IsNested then Some() else None 29 | 30 | let (|IsObsoleteError|_|): MemberInfo -> _ = 31 | MemberInfo.findAttr 32 | "System" 33 | "ObsoleteAttribute" 34 | (fun attr -> 35 | let err = 36 | attr.ConstructorArguments 37 | |> Seq.map (fun arg -> arg.Value) 38 | |> Seq.exists 39 | (function 40 | | :? bool as b when b -> true 41 | | _ -> false) 42 | if err then Some() else None) 43 | 44 | let (|IsPointer|_|) (t: Type) = 45 | if t.IsPointer then t.GetElementType() |> Some else None 46 | 47 | let (|IsMutableStruct|_|) (t: Type) = 48 | let attr = 49 | MemberInfo.findAttr 50 | "System.Runtime.CompilerServices" 51 | "IsReadOnlyAttribute" 52 | Some 53 | t 54 | match attr with 55 | | None when t.IsValueType -> Some() 56 | | _ -> None 57 | 58 | let (|IsSpecialName|_|): MemberInfo -> _ = 59 | function 60 | // MethodInfo is used instead of MethodBase otherwise constructors would always be skipped over. 61 | | :? MethodInfo as mthd when mthd.IsSpecialName -> Some() 62 | | :? FieldInfo as field when field.IsSpecialName -> Some() 63 | | _ -> None 64 | 65 | let (|IsStatic|_|) = 66 | function 67 | | (t: Type) when t.IsSealed && t.IsAbstract -> Some t 68 | | _ -> None 69 | 70 | let (|PropAccessor|_|): MemberInfo -> _ = 71 | let check (mthd: MethodInfo) = 72 | mthd.DeclaringType.GetProperties() 73 | |> Seq.collect (fun prop -> prop.GetAccessors()) 74 | |> Seq.contains mthd 75 | function 76 | | :? MethodInfo as mthd when check mthd -> Some() 77 | | _ -> None 78 | 79 | let rec (|Derives|_|) ns name (t: Type) = 80 | let isBase = TypeInfo.equal ns name 81 | let tbase = 82 | t.BaseType 83 | |> Option.ofObj 84 | |> Option.bind 85 | (function 86 | | super when isBase super -> 87 | Some super 88 | | Derives ns name indirect -> Some indirect 89 | | _ -> None) 90 | let intf = t.GetInterfaces() |> Array.tryFind isBase 91 | match tbase with 92 | | None -> intf 93 | | _ -> tbase 94 | 95 | let (|AssignableTo|_|) ns name = 96 | function 97 | | Derives ns name derived -> Some derived 98 | | t when TypeInfo.equal ns name t -> Some t 99 | | _ -> None 100 | 101 | let (|IsTuple|_|) = 102 | let (|IsTupleType|_|) (t: Type) = 103 | if t.Namespace = "System" && (t.Name.StartsWith "Tuple" || t.Name.StartsWith "ValueTuple") 104 | then Some t 105 | else None 106 | function 107 | | Derives "System.Runtime.CompilerServices" "ITuple" tuple 108 | | IsTupleType tuple -> Some tuple 109 | | _ -> None 110 | 111 | // NOTE: This is a workaround until F# metadata can be read. 112 | // Members whose names end with $W usually use member constraints, see FSharp.Linq.QueryBuilder.AverageByNullable for an example. 113 | let (|FSharpComputationExpressionMemberW|_|) (m: MemberInfo) = 114 | if m.Name.EndsWith "$W" 115 | then Some() 116 | else None 117 | -------------------------------------------------------------------------------- /src/FSharpWrap.Tool/Reflection/Modules.fs: -------------------------------------------------------------------------------- 1 | namespace rec FSharpWrap.Tool.Reflection 2 | 3 | open System 4 | open System.Collections.ObjectModel 5 | open System.Reflection 6 | 7 | open FSharpWrap.Tool 8 | 9 | [] 10 | module private Attributes = 11 | let private argType t ctx = 12 | Type.ref t ctx 13 | |> Option.defaultWith 14 | (fun() -> invalidOp "Type parameters as attribute arguments are not supported") 15 | 16 | let private argValue (value: obj) ctx = 17 | match value with 18 | | null -> AttributeArg.Null 19 | | :? bool as b -> AttributeArg.Bool b 20 | | :? char as c -> AttributeArg.Char c 21 | | :? Double as d -> AttributeArg.Double d 22 | | :? int8 as i -> AttributeArg.Int8 i 23 | | :? int16 as i -> AttributeArg.Int16 i 24 | | :? int32 as i -> AttributeArg.Int32 i 25 | | :? int64 as i -> AttributeArg.Int64 i 26 | | :? ReadOnlyCollection as items -> 27 | Seq.map 28 | (fun item -> argument item ctx) 29 | items 30 | |> List.ofSeq 31 | |> AttributeArg.Array 32 | | :? Single as f -> AttributeArg.Single f 33 | | :? string as str -> AttributeArg.String str 34 | | :? Type as t -> argType t ctx |> AttributeArg.Type 35 | | :? uint8 as ui -> AttributeArg.UInt8 ui 36 | | :? uint16 as ui -> AttributeArg.UInt16 ui 37 | | :? uint32 as ui -> AttributeArg.UInt32 ui 38 | | :? uint64 as ui -> AttributeArg.UInt64 ui 39 | | err -> 40 | let t = err.GetType() 41 | sprintf 42 | "Unsupported attribute argument %O of type %O" 43 | value 44 | t 45 | |> invalidOp 46 | 47 | let argument (arg: CustomAttributeTypedArgument) ctx = 48 | let t = argType arg.ArgumentType ctx 49 | let value = argValue arg.Value ctx 50 | t, value 51 | 52 | let private create (data: CustomAttributeData) ctx = 53 | let attrType = Type.name data.AttributeType ctx 54 | let ctorArgs = 55 | Seq.map 56 | (fun arg -> argument arg ctx) 57 | data.ConstructorArguments 58 | let namedArgs = 59 | Seq.map 60 | (fun (narg: CustomAttributeNamedArgument) -> 61 | let value = argument narg.TypedValue ctx 62 | FsName narg.MemberName, value) 63 | data.NamedArguments 64 | { AttributeType = 65 | Option.defaultWith 66 | (fun() -> invalidOp "Invalid attribute type") 67 | attrType 68 | ConstructorArgs = List.ofSeq ctorArgs 69 | NamedArgs = Map.ofSeq namedArgs } 70 | 71 | let ofMember (mber: MemberInfo) ctx = 72 | mber.CustomAttributes 73 | |> Seq.map (fun attr -> create attr ctx) 74 | |> List.ofSeq 75 | 76 | [] 77 | [] 78 | module private GenericConstraints = 79 | let empty() = { GenericConstraints.Constraints = Set.empty } 80 | let update (constraints: GenericConstraints) items = constraints.Constraints <- items 81 | 82 | [] 83 | module Patterns = 84 | let (|HasGenericConstraints|_|) (tparam: TypeParam) = 85 | match tparam.Constraints with 86 | | { Constraints = Empty } -> None 87 | | _ -> Some tparam.Constraints 88 | 89 | let (|IsNamedType|_|) ns name = 90 | function 91 | | TypeName t when t.Name = FsName name && t.Namespace = Namespace.ofStr ns -> 92 | Some t 93 | | _ -> None 94 | 95 | [] 96 | module Type = 97 | let private typeName (GenericArgs gargs as t) ctx = 98 | let parent = Option.ofObj t.DeclaringType 99 | let parent' = Option.bind (fun p -> name p ctx) parent 100 | let gargs' = 101 | match parent with 102 | | None -> Seq.ofArray gargs 103 | | Some (GenericArgs inherited) -> 104 | Seq.where 105 | (fun garg -> Array.contains garg inherited |> not) 106 | gargs 107 | |> Seq.map (fun garg -> arg garg ctx) 108 | |> TypeArgList.ofSeq 109 | { Name = FsName.ofType t 110 | Namespace = Namespace.ofStr t.Namespace 111 | Parent = parent' 112 | TypeArgs = gargs' } 113 | 114 | let private typeRef t ctx = 115 | match t with 116 | | IsArray elem -> 117 | {| ElementType = arg elem ctx 118 | Rank = t.GetArrayRank() |> uint |} 119 | |> ArrayType 120 | | IsByRef tref -> arg tref ctx |> ByRefType 121 | | IsPointer pnt -> arg pnt ctx |> PointerType 122 | | _ -> typeName t ctx |> TypeName 123 | 124 | let ref t ctx = 125 | match arg t ctx with 126 | | TypeArg tref -> Some tref 127 | | _ -> None 128 | 129 | let name t ctx = 130 | match ref t ctx with 131 | | Some(TypeName tname) -> Some tname 132 | | _ -> None 133 | 134 | let arg t ctx = 135 | match t, ctx with 136 | | HasType existing -> existing 137 | | GenericParam constraints as gen, _ -> 138 | let param = 139 | { Constraints = GenericConstraints.empty() 140 | ParamName = FsName gen.Name } 141 | ctx.TypeParams.Add(gen, param) 142 | let constraints' = 143 | Array.map 144 | (fun ct -> arg ct ctx |> TypeConstraint) 145 | constraints 146 | |> Set.ofArray 147 | GenericConstraints.update param.Constraints constraints' 148 | TypeParam param 149 | | _ -> 150 | let tref = typeRef t ctx 151 | ctx.TypeRefs.Add(t, tref) 152 | TypeArg tref 153 | 154 | let def t ctx = 155 | let tname = 156 | Option.defaultWith 157 | (fun() -> sprintf "Cannot create definition for type %O" t |> invalidOp) 158 | (name t ctx) 159 | let members = 160 | t.GetMembers() 161 | |> Seq.ofArray 162 | |> Seq.where (fun m -> m.DeclaringType = t) 163 | |> Seq.choose 164 | (function 165 | | FSharpComputationExpressionMemberW _ 166 | | IsCompilerGenerated 167 | | IsObsoleteError 168 | | IsSpecialName 169 | | PropAccessor -> None 170 | | mber -> Some mber) 171 | |> Seq.map (fun mber -> Member.ofInfo mber ctx) 172 | |> List.ofSeq 173 | let attrs = Attributes.ofMember t ctx 174 | let intfs = 175 | t.GetInterfaces() 176 | |> Seq.choose (fun intf -> name intf ctx) 177 | |> Set.ofSeq 178 | { Attributes = attrs 179 | Interfaces = intfs 180 | IsAbstract = t.IsAbstract 181 | Members = members 182 | TypeName = tname } 183 | 184 | [] 185 | [] 186 | module AssemblyInfo = 187 | let ofAssembly (assm: Assembly) (ctx: Context) = 188 | let types = 189 | Seq.where 190 | (Filter.typeIncluded ctx.Filter) 191 | assm.ExportedTypes 192 | |> Seq.choose 193 | (function 194 | | Derives "System" "Delegate" _ 195 | | AssignableTo "Microsoft.FSharp.Core" "FSharpFunc`2" _ 196 | | IsNested 197 | // NOTE: This filter currently excludes types such as ImmutableArray from code generation. 198 | | IsMutableStruct 199 | | IsStatic _ 200 | | IsTuple _ -> None 201 | | t -> Some t) 202 | |> Seq.map (fun t -> Type.def t ctx) 203 | |> Seq.toList 204 | { FullName = assm.FullName 205 | Types = types } 206 | 207 | [] 208 | [] 209 | module Member = 210 | let private getType (info: MemberInfo) ctx = 211 | let membertype cond inst stat = 212 | if cond then stat else inst 213 | let mthdparams (m: MethodBase) = 214 | m.GetParameters() 215 | |> List.ofArray 216 | |> List.map 217 | (fun pinfo -> 218 | let argtype = Type.arg pinfo.ParameterType ctx 219 | { ArgType = argtype 220 | IsOptional = 221 | if pinfo.IsOptional 222 | then OptionalParam 223 | else 224 | pinfo.GetCustomAttributesData() 225 | |> Attribute.find 226 | "Microsoft.FSharp.Core" 227 | "OptionalArgumentAttribute" 228 | (fun _ -> Some FsOptionalParam) 229 | |> Option.defaultValue RequiredParam 230 | ParamName = FsName.ofParameter pinfo }) 231 | 232 | match info with 233 | | :? ConstructorInfo as ctor -> mthdparams ctor |> Constructor 234 | | :? FieldInfo as field -> 235 | let ftype = Type.arg field.FieldType ctx 236 | { FieldName = field.Name 237 | FieldType = ftype 238 | IsReadOnly = 239 | if field.IsInitOnly 240 | then ReadOnly 241 | else Mutable } 242 | |> membertype 243 | field.IsStatic 244 | InstanceField 245 | StaticField 246 | | :? PropertyInfo as prop when prop.GetIndexParameters() |> Array.isEmpty -> 247 | let ptype = Type.arg prop.PropertyType ctx 248 | { PropName = prop.Name 249 | Setter = prop.CanWrite 250 | PropType = ptype } 251 | |> membertype 252 | ((prop.GetAccessors() |> Array.head).Attributes.HasFlag MethodAttributes.Static) 253 | InstanceProperty 254 | StaticProperty 255 | | :? MethodInfo as mthd -> 256 | let paramts = mthdparams mthd 257 | let ret = Type.arg mthd.ReturnType ctx 258 | let targs = // TODO: Factor out common code for retrieving generic argument information. 259 | mthd.GetGenericArguments() 260 | |> Array.map (fun garg -> Type.arg garg ctx) 261 | { MethodName = mthd.Name 262 | Params = paramts 263 | RetType = ret 264 | TypeArgs = TypeArgList.ofArray targs } 265 | |> membertype 266 | (mthd.Attributes.HasFlag MethodAttributes.Static) 267 | InstanceMethod 268 | StaticMethod 269 | | _ -> UnknownMember info.Name 270 | 271 | let ofInfo (mber: MemberInfo) ctx = 272 | let mtype = getType mber ctx 273 | let attrs = Attributes.ofMember mber ctx 274 | { Attributes = attrs 275 | Member.Type = mtype } 276 | -------------------------------------------------------------------------------- /src/FSharpWrap.Tool/Reflection/Reflect.fs: -------------------------------------------------------------------------------- 1 | [] 2 | module FSharpWrap.Tool.Reflection.Reflect 3 | 4 | open System.IO 5 | open System.Reflection 6 | 7 | open FSharpWrap.Tool 8 | 9 | let private context r ldf filter = 10 | let included = Filter.assemblyIncluded filter 11 | using 12 | (new MetadataLoadContext(r)) 13 | (fun data -> 14 | let ctx = Context.init filter 15 | ldf data 16 | |> Seq.where included 17 | |> Seq.map 18 | (fun (assm: Assembly) -> AssemblyInfo.ofAssembly assm ctx) 19 | |> List.ofSeq) 20 | 21 | let paths (assms: seq) = 22 | let files = 23 | Seq.collect 24 | (function 25 | | Directory dir -> 26 | Directory.EnumerateFiles(dir.Path, "*.dll", SearchOption.AllDirectories) 27 | | File file -> Seq.singleton file.Path) 28 | assms 29 | context 30 | (PathAssemblyResolver files) 31 | (fun ctx -> 32 | Seq.map 33 | ctx.LoadFromAssemblyPath 34 | files) 35 | -------------------------------------------------------------------------------- /src/FSharpWrap.Tool/Reflection/TypeArgList.fs: -------------------------------------------------------------------------------- 1 | namespace FSharpWrap.Tool.Reflection 2 | 3 | [] 4 | [] 5 | module TypeArgList = 6 | [] 7 | type TypeArgList<'TypeArg> = 8 | private 9 | | TypeArg of 'TypeArg 10 | | TypeArgPair of 'TypeArg * 'TypeArg 11 | | TypeArgs of 'TypeArg[] 12 | 13 | member this.Length = 14 | match this with 15 | | TypeArg _ -> 1 16 | | TypeArgPair _ -> 2 17 | | TypeArgs items -> items.Length 18 | 19 | override this.Equals obj = 20 | this.Length = (obj :?> TypeArgList<'TypeArg>).Length 21 | 22 | override this.GetHashCode() = this.Length 23 | 24 | interface System.IComparable with 25 | member this.CompareTo obj = this.Length - (obj :?> TypeArgList<'TypeArg>).Length 26 | 27 | let empty = TypeArgs Array.empty 28 | let length (targs: TypeArgList<_>) = targs.Length 29 | let ofArray = 30 | function 31 | | [| targ |] -> TypeArg targ 32 | | [| h; t |] -> TypeArgPair(h, t) 33 | | targs -> TypeArgs targs 34 | let ofSeq targs = Seq.toArray targs |> ofArray 35 | let singleton targ = TypeArg targ 36 | let toList = 37 | function 38 | | TypeArg targ -> [ targ ] 39 | | TypeArgPair(h, t) -> [ h; t ] 40 | | TypeArgs targs -> List.ofArray targs 41 | 42 | type TypeArgList<'TypeArg> = TypeArgList.TypeArgList<'TypeArg> 43 | 44 | [] 45 | module TypeArgListPatterns = 46 | let (|TypeArgs|) = TypeArgList.toList 47 | -------------------------------------------------------------------------------- /src/FSharpWrap.Tool/Reflection/Types.fs: -------------------------------------------------------------------------------- 1 | namespace rec FSharpWrap.Tool.Reflection 2 | 3 | open System.Collections 4 | open System.Collections.Generic 5 | 6 | open FSharpWrap.Tool 7 | 8 | [] 9 | type AttributeArg = 10 | | Array of (TypeRef * AttributeArg) list 11 | | Bool of bool 12 | | Char of char 13 | | Double of System.Double 14 | | Int8 of int8 15 | | Int16 of int16 16 | | Int32 of int32 17 | | Int64 of int64 18 | | Null 19 | | Single of System.Single 20 | | String of string 21 | | Type of TypeRef 22 | | UInt8 of uint8 23 | | UInt16 of uint16 24 | | UInt32 of uint32 25 | | UInt64 of uint64 26 | 27 | type AttributeInfo = 28 | { AttributeType: TypeName 29 | ConstructorArgs: (TypeRef * AttributeArg) list 30 | NamedArgs: Map } 31 | 32 | [] 33 | type GenericConstraint = 34 | | TypeConstraint of TypeArg 35 | 36 | [] 37 | type GenericConstraints = 38 | private { mutable Constraints: Set } 39 | 40 | interface IEnumerable with 41 | member this.GetEnumerator() = (this.Constraints :> IEnumerable<_>).GetEnumerator() 42 | interface IEnumerable with 43 | member this.GetEnumerator() = (this.Constraints :> IEnumerable).GetEnumerator() 44 | 45 | static member Empty() = { Constraints = Set.empty } 46 | 47 | [] 48 | type TypeParam = 49 | { Constraints: GenericConstraints 50 | ParamName: FsName } 51 | 52 | type TypeArgList = TypeArgList 53 | 54 | [] 55 | type TypeName = 56 | { Name: FsName 57 | Namespace: Namespace 58 | Parent: TypeName option 59 | TypeArgs: TypeArgList } 60 | 61 | [] 62 | type TypeRef = 63 | | ArrayType of 64 | {| ElementType: TypeArg 65 | Rank: uint |} 66 | | ByRefType of TypeArg 67 | | FsFuncType of TypeArg * TypeArg 68 | | InferredType 69 | | PointerType of TypeArg 70 | | TypeName of TypeName 71 | 72 | [] 73 | type TypeArg = 74 | | TypeArg of TypeRef 75 | | TypeParam of TypeParam 76 | 77 | type ParamOptional = 78 | | FsOptionalParam 79 | | OptionalParam 80 | | RequiredParam 81 | 82 | type Param = 83 | { ArgType: TypeArg 84 | IsOptional: ParamOptional 85 | ParamName: FsName } 86 | 87 | type ReadOnly = ReadOnly | Mutable 88 | 89 | type Field = 90 | { FieldName: string 91 | FieldType: TypeArg 92 | IsReadOnly: ReadOnly } 93 | 94 | type Method = 95 | { MethodName: string 96 | Params: Param list 97 | RetType: TypeArg 98 | TypeArgs: TypeArgList } 99 | 100 | // TODO: How to handle properties with parameters, maybe handle them as methods instead? 101 | type Property = 102 | { PropName: string 103 | PropType: TypeArg 104 | Setter: bool } 105 | 106 | type MemberType = 107 | | Constructor of Param list 108 | | InstanceField of Field 109 | | InstanceMethod of Method 110 | | InstanceProperty of Property 111 | | StaticField of Field 112 | | StaticMethod of Method 113 | | StaticProperty of Property 114 | | UnknownMember of name: string 115 | 116 | type Member = 117 | { Attributes: AttributeInfo list 118 | Type: MemberType } 119 | 120 | [] 121 | type TypeDef = 122 | { Attributes: AttributeInfo list 123 | Interfaces: Set 124 | IsAbstract: bool 125 | Members: Member list 126 | TypeName: TypeName } 127 | 128 | override this.Equals obj = this.TypeName = (obj :?> TypeDef).TypeName 129 | override this.GetHashCode() = this.TypeName.GetHashCode() 130 | 131 | interface System.IComparable with 132 | member this.CompareTo obj = 133 | compare this.TypeName (obj :?> TypeDef).TypeName 134 | 135 | type AssemblyInfo = 136 | { FullName: string 137 | Types: TypeDef list } 138 | -------------------------------------------------------------------------------- /src/FSharpWrap.Tool/Utils.fs: -------------------------------------------------------------------------------- 1 | namespace FSharpWrap.Tool 2 | 3 | open System 4 | open System.Reflection 5 | 6 | [] 7 | module internal Collections = 8 | let inline (|Empty|NotEmpty|) col = 9 | if (^T : (member IsEmpty : bool) col) 10 | then Choice1Of2() 11 | else Choice2Of2 col 12 | 13 | let inline (|ContainsValue|_|) key col = 14 | let mutable value = Unchecked.defaultof<'Value> 15 | if (^T : (member TryGetValue : 'Key * byref<'Value> -> bool) (col, key, &value)) 16 | then Some value 17 | else None 18 | 19 | [] 20 | module String = 21 | let toCamelCase = 22 | String.mapi 23 | (function 24 | | 0 -> Char.ToLower 25 | | _ -> id) 26 | 27 | let toLiteral (str: string) = 28 | str.Replace("\"", "\"\"") |> sprintf " @\"%s\"" 29 | 30 | let (|OneOf|_|) (values: string list) = 31 | let values' = Set.ofList values 32 | fun str -> 33 | if Set.contains str values' 34 | then Some() 35 | else None 36 | 37 | [] 38 | module internal TypeInfo = 39 | let inline equal ns name (t: System.Type) = 40 | t.Name = name && t.Namespace = ns 41 | 42 | [] 43 | module internal Attribute = 44 | let find ns name chooser (source: seq) = 45 | source 46 | |> Seq.where 47 | (fun attr -> TypeInfo.equal ns name attr.AttributeType) 48 | |> Seq.tryPick chooser 49 | 50 | let ctorArgs<'arg> (data: CustomAttributeData) = 51 | data.ConstructorArguments 52 | |> Seq.map 53 | (fun arg -> 54 | match arg.Value with 55 | | :? 'arg as arg' -> Some arg' 56 | | _ -> None) 57 | |> List.ofSeq 58 | 59 | [] 60 | module internal MemberInfo = 61 | let findAttr ns name chooser (m: MemberInfo) = 62 | m.GetCustomAttributesData() |> Attribute.find ns name chooser 63 | 64 | let compiledName (mber: MemberInfo) = 65 | findAttr 66 | "Microsoft.FSharp.Core" 67 | "CompiledNameAttribute" 68 | (fun attr -> 69 | attr.ConstructorArguments 70 | |> Seq.map (fun arg -> arg.Value) 71 | |> Seq.tryHead 72 | |> Option.bind 73 | (function 74 | | :? string as str -> 75 | if str.StartsWith "FSharp" then 76 | str.Substring 6 77 | else 78 | // TODO: Get actual name of type from the F# metadata. 79 | // sprintf "Cannot original name of member %s" mber.Name |> invalidOp 80 | str 81 | |> Some 82 | | _ -> None)) 83 | mber 84 | |> Option.defaultValue mber.Name 85 | -------------------------------------------------------------------------------- /src/FSharpWrap.Tool/paket.references: -------------------------------------------------------------------------------- 1 | FSharp.Core 2 | System.Reflection.MetadataLoadContext 3 | -------------------------------------------------------------------------------- /src/FSharpWrap/.gitignore: -------------------------------------------------------------------------------- 1 | tool/ 2 | -------------------------------------------------------------------------------- /src/FSharpWrap/FSharpWrap.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | davnavr 5 | Generates F# modules and functions from non-F# dependencies. 6 | true 7 | $Name$ 8 | Apache-2.0 9 | https://davnavr.github.io/FSharpWrap/ 10 | $PackageReleaseNotes$ 11 | 12 | f# fsharp codegen utils helpers 13 | $Name$ 14 | $PackageVersion$ 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/FSharpWrap/FSharpWrap.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | (6); 36 | args.Add(ToolPath); 37 | args.AddRange(AssemblyPaths); 38 | args.Add("--output-file"); 39 | args.Add(OutputFile); 40 | 41 | if (ExcludeAssemblyNames.Length > 0) 42 | { 43 | args.Add("--exclude-assembly-names"); 44 | args.AddRange(ExcludeAssemblyNames); 45 | } 46 | 47 | if (IncludeAssemblyNames.Length > 0) 48 | { 49 | args.Add("--include-assembly-names"); 50 | args.AddRange(IncludeAssemblyNames); 51 | } 52 | 53 | if (ExcludeNamespaces.Length > 0) 54 | { 55 | args.Add("--exclude-namespaces"); 56 | args.AddRange(ExcludeNamespaces); 57 | } 58 | 59 | if (IncludeNamespaces.Length > 0) 60 | { 61 | args.Add("--include-namespaces"); 62 | args.AddRange(IncludeNamespaces); 63 | } 64 | 65 | if (LaunchDebugger) args.Add("--launch-debugger"); 66 | 67 | CliArguments = String.Join(" ", args.ConvertAll(arg => $"\"{arg}\"")); 68 | ]]> 69 | 70 | 71 | 72 | 73 | 74 | <_FSharpWrapLaunchDebugger Condition="'$(_FSharpWrapLaunchDebugger)'==''">false 75 | <_FSharpWrapToolPath Condition="'$(_FSharpWrapToolPath)'==''">$(MSBuildThisFileDirectory)/FSharpWrap.Tool.dll 76 | 77 | 78 | 79 | $(MSBuildProjectDirectory)/output.autogen.fs 80 | $(MSBuildProjectDirectory)/output.$(TargetFramework).autogen.fs 81 | 82 | 83 | 84 | 88 | 89 | 90 | 91 | 100 | 101 | 102 | 103 | 104 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | *.autogen.fs 2 | -------------------------------------------------------------------------------- /test/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /test/FSharpWrap.Benchmarks/Benchmarks.fs: -------------------------------------------------------------------------------- 1 | module FSharpWrap.Tool.Benchmarks 2 | 3 | open System.Reflection 4 | 5 | open BenchmarkDotNet.Attributes 6 | open BenchmarkDotNet.Configs 7 | open BenchmarkDotNet.Running 8 | 9 | open FSharpWrap.Tool 10 | open FSharpWrap.Tool.Reflection 11 | open FSharpWrap.Tool.Generation 12 | 13 | let inline private assemblies() = 14 | Context.init Filter.Empty 15 | |> AssemblyInfo.ofAssembly 16 | (typeof.Assembly) 17 | |> List.singleton 18 | 19 | type PrintData = 20 | { Name: string 21 | Print: Printer } 22 | 23 | override this.ToString() = this.Name 24 | 25 | [] 26 | [] 27 | [] 28 | type Benchmarks() = 29 | let assms = assemblies() 30 | let file = Generate.fromAssemblies assms 31 | let out = 32 | { Close = ignore 33 | Line = ignore 34 | Write = ignore } 35 | 36 | [] 37 | member _.Reflect() = assemblies() 38 | [] 39 | member _.GenerateCode() = Generate.fromAssemblies assms 40 | [] 41 | member _.PrintCode() = Print.genFile file out 42 | 43 | [] 44 | let main argv = 45 | let assm = Assembly.GetExecutingAssembly() 46 | BenchmarkSwitcher 47 | .FromAssembly(assm) 48 | .Run(args = argv) 49 | |> ignore 50 | 0 51 | -------------------------------------------------------------------------------- /test/FSharpWrap.Benchmarks/FSharpWrap.Benchmarks.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | FSharpWrap.Benchmarks 5 | Exe 6 | net5.0;netcoreapp3.1 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/FSharpWrap.Benchmarks/paket.references: -------------------------------------------------------------------------------- 1 | group Test 2 | BenchmarkDotNet 3 | -------------------------------------------------------------------------------- /test/FSharpWrap.Tool.Tests/FSharpWrap.Tool.Tests.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | FSharpWrap.Tool.Tests 5 | Exe 6 | netcoreapp3.1 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/FSharpWrap.Tool.Tests/Gen.fs: -------------------------------------------------------------------------------- 1 | [] 2 | module FSharpWrap.Tool.Tests.Gen 3 | 4 | open FsCheck 5 | 6 | open System 7 | 8 | open FSharpWrap.Tool 9 | 10 | let ws = 11 | gen { 12 | let! len = Gen.choose(0, 10) 13 | return String.replicate len " " 14 | } 15 | 16 | let chars: seq -> _ = 17 | Gen.elements 18 | >> Gen.arrayOf 19 | >> Gen.resize 7 20 | >> Gen.map String 21 | 22 | let path = 23 | let name = 24 | [ 25 | [ 'a'..'z' ] 26 | [ 'A'..'Z' ] 27 | [ '0'..'9' ] 28 | [ '_'; ' ' ] 29 | ] 30 | |> List.collect id 31 | |> chars 32 | let sep = Gen.elements [ '\\'; '/' ] 33 | gen { 34 | let! drive = 35 | [ 36 | [ 'A'..'E' ] 37 | |> Gen.elements 38 | |> Gen.map (sprintf "%c:") 39 | 40 | Gen.constant "" 41 | ] 42 | |> Gen.oneof 43 | let! dir = 44 | Gen.map2 45 | (sprintf "%s%c") 46 | name 47 | sep 48 | |> Gen.arrayOf 49 | |> Gen.resize 6 50 | |> Gen.map String.Concat 51 | let! file = name 52 | let! ext = Gen.resize 4 name 53 | return 54 | sprintf "%s%s%s.%s" drive dir file ext 55 | |> Path.ofStr 56 | |> Option.get 57 | } 58 | -------------------------------------------------------------------------------- /test/FSharpWrap.Tool.Tests/GenerateTests.fs: -------------------------------------------------------------------------------- 1 | module FSharpWrap.Tool.Tests.GenerateTests 2 | 3 | open Expecto 4 | 5 | [] 6 | let tests = 7 | testList "code generation" [ 8 | // TODO: Consider using the F# compiler services to determine that the generated code contains what is expected and is syntactically correct. 9 | ] 10 | -------------------------------------------------------------------------------- /test/FSharpWrap.Tool.Tests/OptionsTests.fs: -------------------------------------------------------------------------------- 1 | module FSharpWrap.Tool.Tests.OptionsTests 2 | 3 | open Expecto 4 | open FsCheck 5 | 6 | open FSharpWrap.Tool 7 | 8 | type ArgumentsWithHelp = 9 | private 10 | | ArgumentsWithHelp of string list 11 | 12 | type InvalidArgumentOptions = 13 | private 14 | | InvalidArgumentOptions of string list 15 | 16 | type ValidArguments = 17 | private 18 | | ValidArguments of string list 19 | 20 | [] 21 | module Generators = 22 | let private option name = 23 | Gen.map 24 | (sprintf "--%s%s" name) 25 | Gen.ws 26 | 27 | let private arguments more t = 28 | gen { 29 | let! assemblies = 30 | Gen.path 31 | |> Gen.nonEmptyListOf 32 | |> Gen.resize 6 33 | |> Gen.map (List.map string) 34 | let! outfile = 35 | gen { 36 | let! opt = option "output-file" 37 | let! file = Gen.map string Gen.path 38 | return [ opt; file ] 39 | } 40 | let! debug = Gen.elements [ []; [ "--launch-debugger" ] ] 41 | let! rest = 42 | [ 43 | outfile 44 | debug 45 | more 46 | ] 47 | |> Gen.shuffle 48 | |> Gen.map (List.ofArray >> List.collect id) 49 | return t (assemblies @ rest) 50 | } 51 | 52 | type ArgumentGenerators = 53 | static member ArgumentsWithHelp() = 54 | arguments 55 | [ "--help" ] 56 | ArgumentsWithHelp 57 | |> Arb.fromGen 58 | 59 | static member InvalidArgumentOptions() = 60 | let badopt = 61 | gen { 62 | let! name = 63 | [ 64 | [ 'a'..'z' ] 65 | [ 'A'..'Z' ] 66 | [ '-' ] 67 | ] 68 | |> List.collect id 69 | |> Gen.chars 70 | return! option name 71 | } 72 | |> Gen.filter (fun str -> Map.containsKey str Options.all |> not) 73 | badopt 74 | |> Gen.listOf 75 | |> Gen.map InvalidArgumentOptions 76 | |> Arb.fromGen 77 | 78 | static member ValidArguments() = 79 | ValidArguments 80 | |> arguments [] 81 | |> Arb.fromGen 82 | 83 | module private Expect = 84 | let parseError msg args = 85 | Expect.isError 86 | (Options.parse args) 87 | msg 88 | 89 | [] 90 | let tests = 91 | let config = 92 | { FsCheckConfig.defaultConfig with 93 | arbitrary = 94 | typeof :: FsCheckConfig.defaultConfig.arbitrary } 95 | let argumentsProperty name = 96 | testPropertyWithConfig 97 | config 98 | name 99 | let parsingProperty reason check expect = 100 | check 101 | >> expect reason 102 | |> argumentsProperty reason 103 | let successfulParse reason f = 104 | parsingProperty 105 | reason 106 | (fun (ValidArguments args) -> args) 107 | (fun msg argv -> 108 | let args = 109 | Expect.wantOk (Options.parse argv) "Parsing unexpectedly failed" 110 | f argv args msg) 111 | 112 | testList "argument parsing tests" [ 113 | parsingProperty 114 | "parsing fails when --help is specified" 115 | (fun (ArgumentsWithHelp args) -> args) 116 | Expect.parseError 117 | 118 | parsingProperty 119 | "parsing fails when invalid flag is specified" 120 | (fun (InvalidArgumentOptions args) -> args) 121 | Expect.parseError 122 | 123 | successfulParse 124 | "parsed arguments should contain validated output path" 125 | (fun argv args -> string args.OutputFile |> Expect.contains argv) 126 | 127 | successfulParse 128 | "parsed arguments should contain validated assembly paths" 129 | (fun argv args -> 130 | args.Assemblies 131 | |> List.map string 132 | |> Expect.containsAll argv) 133 | 134 | successfulParse 135 | "parsed arguments should specify debugger launch" 136 | (fun argv args -> 137 | List.contains 138 | "--launch-debugger" 139 | argv 140 | |> Expect.equal args.LaunchDebugger) 141 | 142 | testCase "output file cannot be specified twice" <| fun() -> 143 | let result = 144 | [ 145 | "./MyAssembly.dll" 146 | "--output-file" 147 | "./File1.fs" 148 | "--output-file" 149 | "./File2.fs" 150 | ] 151 | |> Options.parse 152 | 153 | Expect.equal result (Error MultipleOutputFiles) "Parsing should fail because --output-file is specified more than once" 154 | 155 | testCase "included assemblies can be specified more than once" <| fun() -> 156 | let result = 157 | [ 158 | "./Hello/World.dll" 159 | "--output-file" 160 | "./Temp/Thing.fs" 161 | "--include-assembly-names" 162 | "FancyParsing" 163 | "Keyboard" 164 | "My.Thing" 165 | "--include-assembly-names" 166 | "CI" 167 | ] 168 | |> Options.parse 169 | Expect.isOk result "Parsing should succeed with options expecting lists" 170 | 171 | testCase "cannot have mixed filter for assembly names" <| fun() -> 172 | let result = 173 | [ 174 | "./FSharpWrap.Tool.dll" 175 | "--output-file" 176 | "./fun.fs" 177 | "--include-assembly-names" 178 | "One" 179 | "--exclude-assembly-names" 180 | "Two" 181 | ] 182 | |> Options.parse 183 | Expect.equal result (Error MixedFilter) "Parsing should fail because assembly file filter is mixed" 184 | ] 185 | -------------------------------------------------------------------------------- /test/FSharpWrap.Tool.Tests/Test.fs: -------------------------------------------------------------------------------- 1 | module FSharpWrap.Tool.Tests.Test 2 | 3 | open Expecto 4 | 5 | [] 6 | let main argv = runTestsInAssemblyWithCLIArgs Seq.empty argv 7 | -------------------------------------------------------------------------------- /test/TestProject.CSharpDependency/MyCustomList.cs: -------------------------------------------------------------------------------- 1 | namespace CSharpDependency 2 | { 3 | using System; 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | 8 | /// 9 | /// A naive implementation for an immutable list. 10 | /// 11 | /// The type of the item. 12 | public class MyCustomList : IEnumerable 13 | { 14 | private readonly T[] items; 15 | 16 | public MyCustomList() : this(new T[0]) { } 17 | public MyCustomList(IEnumerable items) : this(items.ToArray()) { } 18 | private MyCustomList(T[] items) => this.items = items; 19 | 20 | public MyCustomList Add(T item) 21 | { 22 | var last = this.items.LongLength; 23 | var replacement = new T[last + 1L]; 24 | Array.Copy(this.items, replacement, last); 25 | replacement[last] = item; 26 | return new MyCustomList(replacement); 27 | } 28 | 29 | public MyCustomList AddRange(IEnumerable items) 30 | { 31 | var adding = items.ToArray(); 32 | var replacement = new T[this.items.LongLength + adding.LongLength]; 33 | Array.Copy(this.items, 0L, replacement, 0L, this.items.LongLength); 34 | Array.Copy(adding, 0L, replacement, this.items.LongLength, adding.LongLength); 35 | return new MyCustomList(replacement); 36 | } 37 | 38 | public IEnumerator GetEnumerator() => this.items.Cast().GetEnumerator(); 39 | IEnumerator IEnumerable.GetEnumerator() => this.items.GetEnumerator(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /test/TestProject.CSharpDependency/MyString.cs: -------------------------------------------------------------------------------- 1 | namespace CSharpDependency 2 | { 3 | public class MyString 4 | { 5 | public readonly string value; 6 | 7 | public MyString(string value) => this.value = value; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/TestProject.CSharpDependency/TestProject.CSharpDependency.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | netstandard2.0 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /test/TestProject.CSharpDependency/TestProject.CSharpDependency.csproj.paket.references: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davnavr/FSharpWrap/a2f22c05c26de29796917d4bd24c65fcc2035cbf/test/TestProject.CSharpDependency/TestProject.CSharpDependency.csproj.paket.references -------------------------------------------------------------------------------- /test/TestProject.CSharpDependent/Program.fs: -------------------------------------------------------------------------------- 1 | module Program 2 | 3 | open Expecto 4 | 5 | open System.Collections.Generic 6 | open System.Diagnostics 7 | 8 | open CSharpDependency 9 | 10 | [] 11 | let main argv = 12 | testList "project reference tests" [ 13 | testCase "list expression is equivalent" <| fun() -> 14 | let exp = List.collect id [ [ 'a'..'z' ]; [ 'A'..'Z' ] ] 15 | let act = 16 | List.expr { 17 | yield! [ 'a'..'z' ] 18 | for c in [ 'A'..'Z' ] do yield c 19 | } 20 | Expect.sequenceEqual act exp "Lists should be equivalent" 21 | 22 | testProperty "constructor produces equal value" <| fun str -> 23 | let exp = MyString(str).value 24 | let act = MyString.ofString str |> MyString.value 25 | Expect.equal act exp "Two objects must be equal" 26 | 27 | testCase "code generated for implicitly included class" <| fun() -> 28 | let frame = new StackTrace() 29 | let exp = frame.GetFrame(0) 30 | Expect.equal (StackTrace.getFrame 0 frame) exp "Property values should be equal" 31 | 32 | testList "custom collection" [ 33 | testProperty "ofSeq uses same items" <| fun (items: string list) -> 34 | Expect.sequenceEqual 35 | (MyCustomList.ofSeq items) 36 | items 37 | "Collections should be the same" 38 | 39 | testProperty "computation expression works" <| fun one (rest: (string * string) list) -> 40 | let exp = one :: rest 41 | let act = MyCustomList.expr { one; yield! rest } 42 | Expect.sequenceEqual act exp "Both sequences should be the same" 43 | ] 44 | ] 45 | |> runTestsWithCLIArgs Seq.empty argv 46 | -------------------------------------------------------------------------------- /test/TestProject.CSharpDependent/TestProject.CSharpDependent.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | OtherFileName.autogen.fs 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /test/TestProject.Collections/Test.fs: -------------------------------------------------------------------------------- 1 |  2 | open FsCheck 3 | 4 | open Expecto 5 | 6 | open System 7 | open System.Collections.Generic 8 | open System.Collections.Immutable 9 | open System.Collections.ObjectModel 10 | 11 | let hello() = 12 | let dictionary: ImmutableDictionary = 13 | ImmutableDictionary.expr { 14 | yield "word", "the thing to the left" 15 | yield "dictionary", "what this is" 16 | } 17 | () 18 | 19 | type CollectionGenerator = 20 | static member List() = 21 | Arb.generate<_ list> 22 | |> Gen.map List<_> 23 | |> Arb.fromGen 24 | 25 | static member ImmutableList() = 26 | Gen.map ImmutableList.CreateRange Arb.generate<_ list> |> Arb.fromGen 27 | 28 | [] 29 | let main argv = 30 | let config = 31 | { FsCheckConfig.defaultConfig with 32 | arbitrary = typeof :: FsCheckConfig.defaultConfig.arbitrary } 33 | let inline testCollection name = 34 | testPropertyWithConfig config name 35 | 36 | testList "collection generation tests" [ 37 | testCollection "constructor call is equal" <| fun (items: List) -> 38 | Expect.sequenceEqual 39 | (ReadOnlyCollection.ofIList items) 40 | (ReadOnlyCollection items) 41 | "The collections should call the same constructor" 42 | 43 | testCollection "active pattern is equal" <| fun (items: ImmutableList<_>) -> 44 | ImmutableList.(|IsEmpty|_|) items |> Option.isSome = items.IsEmpty 45 | 46 | testCollection "property values are equal" <| fun (items: ImmutableList<_>) -> 47 | ImmutableList.count items = items.Count 48 | 49 | testCase "computation expressions produce equal value" <| fun() -> 50 | let ce = 51 | ImmutableList.expr { 52 | 3 53 | 1 54 | 4 55 | 1 56 | 5 57 | yield! [ 9; 2; 6; 5 ] 58 | } 59 | let exp = 60 | ImmutableList.CreateRange [ 3; 1; 4; 1; 5; 9; 2; 6; 5 ] 61 | Expect.sequenceEqual ce exp "Both lists should contain the same elments in the same order" 62 | 63 | testProperty "computation expression singletons should be equal" <| fun (item: uint32) -> 64 | Expect.sequenceEqual 65 | (ImmutableList.expr { item }) 66 | (ImmutableList.Create item) 67 | "Both lists should contain the same element" 68 | 69 | testProperty "computation expression is correct for mutable type" <| fun(items: string list) -> 70 | Expect.sequenceEqual 71 | (List.expr { yield! items }) 72 | items 73 | "List should contain same items in same order as sequence" 74 | 75 | testCollection "adding items is equal" <| fun (initial: ImmutableList) add -> 76 | let exp = initial.Add add 77 | let act = ImmutableList.add add initial 78 | Expect.sequenceEqual act exp "The lists should contain the same elements when an item is added" 79 | 80 | testCollection "multiple parameters" <| fun (items: ImmutableList) vold vnew -> 81 | let exp = items.Add(vold).Replace(vold, vnew) 82 | let act = ImmutableList.add vold items |> ImmutableList.replace vold vnew 83 | Expect.sequenceEqual act exp "The lists should replace the same element" 84 | 85 | testProperty "computation expression works with conditions" <| fun (one: string list) (two: string list) cond -> 86 | let exp = 87 | let items = List<_>() 88 | items.AddRange one 89 | if cond then 90 | items.AddRange two 91 | items 92 | let act = 93 | List.expr { 94 | yield! one 95 | if cond then 96 | yield! two 97 | } 98 | Expect.sequenceEqual act exp "The lists should contain the same elements with the same condition" 99 | ] 100 | |> runTestsWithCLIArgs Seq.empty argv 101 | -------------------------------------------------------------------------------- /test/TestProject.Collections/TestProject.Collections.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/TestProject.MultiTarget/Test.fs: -------------------------------------------------------------------------------- 1 | module MultiTarget.Tests 2 | 3 | open Expecto 4 | 5 | open System 6 | 7 | let getAssembly (t: Type) = 8 | Type.assembly t 9 | 10 | [] 11 | let main argv = 12 | testList "multi-target tests" [ 13 | testCase "assemblies are equal" <| fun() -> 14 | let t = typeof 15 | Expect.equal (Type.assembly t) t.Assembly "Generated function should return equal object" 16 | #if NET5_0 17 | testCase "target framework dependent code works" <| fun() -> 18 | // TODO: Find a function that is only generated for .NET 5 19 | let target = typeof 20 | let t = typeof 21 | Expect.equal 22 | (Type.isAssignableTo target t) 23 | (t.IsAssignableTo target) 24 | "Results should be equal" 25 | #endif 26 | ] 27 | |> runTestsWithCLIArgs Seq.empty argv 28 | -------------------------------------------------------------------------------- /test/TestProject.MultiTarget/TestProject.MultiTarget.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp3.1;net5.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/TestProject.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <_FSharpWrapToolPath>$(RootDirectory)/src/FSharpWrap.Tool/bin/Release/netcoreapp3.1/FSharpWrap.Tool.dll 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/paket.references: -------------------------------------------------------------------------------- 1 | group Test 2 | Expecto 3 | Expecto.FsCheck 4 | System.Collections.Immutable 5 | --------------------------------------------------------------------------------