From 9e305c5079513d0c09a756e5996f02a58a4e8802 Mon Sep 17 00:00:00 2001 From: Alfonso Garcia-Caro Date: Sat, 12 Nov 2022 11:49:05 +0900 Subject: [PATCH 1/3] Parse projects as .csproj --- src/Fable.Cli/Fable.Cli.fsproj | 4 +- src/Fable.Cli/ProjectCracker.fs | 90 ++++++++++++++------ src/Fable.Cli/Util.fs | 5 ++ src/Fable.Transforms/Fable.Transforms.fsproj | 1 + 4 files changed, 71 insertions(+), 29 deletions(-) diff --git a/src/Fable.Cli/Fable.Cli.fsproj b/src/Fable.Cli/Fable.Cli.fsproj index b335bb23d4..dc3877559f 100644 --- a/src/Fable.Cli/Fable.Cli.fsproj +++ b/src/Fable.Cli/Fable.Cli.fsproj @@ -17,6 +17,7 @@ fable true F# to JS compiler + $(OtherFlags) --nowarn:3536 @@ -36,6 +37,7 @@ + @@ -44,7 +46,7 @@ - + diff --git a/src/Fable.Cli/ProjectCracker.fs b/src/Fable.Cli/ProjectCracker.fs index cf414b512a..9f74a2ea35 100644 --- a/src/Fable.Cli/ProjectCracker.fs +++ b/src/Fable.Cli/ProjectCracker.fs @@ -12,6 +12,8 @@ open Fable.AST open Globbing.Operators open Buildalyzer +let [] TARGET_FRAMEWORK = "net6.0" + type FablePackage = { Id: string Version: string @@ -311,14 +313,19 @@ let getSourcesFromFablePkg (projFile: string) = | path -> [ path ] |> List.map Path.normalizeFullPath) -let private isUsefulOption (opt : string) = - [ "--define" - "--nowarn" - "--warnon" +let private extractUsefulOptionsAndSources (line: string) (accSources: string list, accOptions: string list) = + if line.StartsWith("-") then // "--warnaserror" // Disable for now to prevent unexpected errors, see #2288 // "--langversion" // See getBasicCompilerArgs - ] - |> List.exists opt.StartsWith + if line.StartsWith("--nowarn") || line.StartsWith("--warnon") then + accSources, line::accOptions + elif line.StartsWith("--define:") then + let defines = line.Substring(9).Split(';') |> Array.mapToList (fun d -> "--define:" + d) + accSources, defines @ accOptions + else + accSources, accOptions + else + (Path.normalizeFullPath line)::accSources, accOptions let excludeProjRef (opts: CrackerOptions) (dllRefs: IDictionary) (projRef: string) = let projName = Path.GetFileNameWithoutExtension(projRef) @@ -351,12 +358,8 @@ let getCrackedFsproj (opts: CrackerOptions) (projOpts: string[]) (projRefs: stri let dllName = getDllName line dllRefs.Add(dllName, line) src, otherOpts - elif isUsefulOption line then - src, line::otherOpts - elif line.StartsWith("-") then - src, otherOpts else - (Path.normalizeFullPath line)::src, otherOpts) + extractUsefulOptionsAndSources line (src, otherOpts)) let fablePkgs = let dllRefs' = dllRefs |> Seq.map (fun (KeyValue(k,v)) -> k,v) |> Seq.toArray @@ -397,7 +400,7 @@ let getProjectOptionsFromProjectFile = if Path.IsPathRooted f then f else Path.Combine(projDir, f) else f - fun (opts: CrackerOptions) projFile -> + fun (opts: CrackerOptions) (projFile: string) -> let manager = match manager with | Some m -> m @@ -406,25 +409,63 @@ let getProjectOptionsFromProjectFile = let options = AnalyzerManagerOptions(LogWriter = log) let m = AnalyzerManager(options) m.SetGlobalProperty("Configuration", opts.Configuration) + m.SetGlobalProperty("TargetFramework", TARGET_FRAMEWORK) for define in opts.FableOptions.Define do m.SetGlobalProperty(define, "true") manager <- Some m m - let analyzer = manager.GetProject(projFile) - // If the project targets multiple frameworks, multiple results will be returned - // For now we just take the first one with non-empty command - let result = - analyzer.Build() + let tryGetResult (getCompilerArgs: IAnalyzerResult -> string[]) (projFile: string) = + let analyzer = manager.GetProject(projFile) + let env = analyzer.EnvironmentFactory.GetBuildEnvironment(Environment.EnvironmentOptions(DesignTime=true,Restore=false)) + // If the project targets multiple frameworks, multiple results will be returned + // For now we just take the first one with non-empty command + let results = analyzer.Build(env) + results |> Seq.tryFind (fun r -> String.IsNullOrEmpty(r.Command) |> not) + |> Option.map (fun result -> + {| CompilerArguments = getCompilerArgs result + ProjectReferences = result.ProjectReferences + Properties = result.Properties |}) + + let csprojResult = + let csprojFile = projFile.Replace(".fsproj", ".csproj") + if IO.File.Exists(csprojFile) then + None + else + try + System.IO.File.Copy(projFile, csprojFile) + projFile.Replace(".fsproj", ".csproj") + |> tryGetResult (fun r -> + // Careful, options for .csproj start with / but so do root paths in unix + let reg = System.Text.RegularExpressions.Regex(@"^\/[^\/]+?(:?:|$)") + let comArgs = + r.CompilerArguments + |> Array.map (fun line -> + if reg.IsMatch(line) then + if line.StartsWith("/reference") then "-r" + line.Substring(10) + else "--" + line.Substring(1) + else line) + match r.Properties.TryGetValue("OtherFlags") with + | false, _ -> comArgs + | true, otherFlags -> + let otherFlags = otherFlags.Split(' ', StringSplitOptions.RemoveEmptyEntries) + Array.append otherFlags comArgs) + finally + File.safeDelete csprojFile + + let result = + csprojResult + |> Option.orElseWith (fun () -> projFile |> tryGetResult (fun r -> + // result.CompilerArguments doesn't seem to work well in Linux + System.Text.RegularExpressions.Regex.Split(r.Command, @"\r?\n"))) |> function | Some result -> result // TODO: Get Buildalyzer errors from the log | None -> $"Cannot parse {projFile}" |> Fable.FableError |> raise let projDir = IO.Path.GetDirectoryName(projFile) let projOpts = - // result.CompilerArguments doesn't seem to work well in Linux - System.Text.RegularExpressions.Regex.Split(result.Command, @"\r?\n") + result.CompilerArguments |> Array.skipWhile (fun line -> not(line.StartsWith("-"))) |> Array.map (compileFilesToAbsolutePath projDir) projOpts, Seq.toArray result.ProjectReferences, result.Properties @@ -437,6 +478,7 @@ let fullCrack (opts: CrackerOptions): CrackedFsproj = Process.runSync (IO.Path.GetDirectoryName opts.ProjFile) "dotnet" [ "restore" IO.Path.GetFileName opts.ProjFile + $"-p:TargetFramework={TARGET_FRAMEWORK}" for constant in opts.FableOptions.Define do $"-p:{constant}=true" ] |> ignore @@ -459,15 +501,7 @@ let easyCrack (opts: CrackerOptions) dllRefs (projFile: string): CrackedFsproj = getProjectOptionsFromProjectFile opts projFile let outputType = ReadOnlyDictionary.tryFind "OutputType" msbuildProps - let sourceFiles, otherOpts = - (projOpts, ([], [])) - ||> Array.foldBack (fun line (src, otherOpts) -> - if isUsefulOption line then - src, line::otherOpts - elif line.StartsWith("-") then - src, otherOpts - else - (Path.normalizeFullPath line)::src, otherOpts) + let sourceFiles, otherOpts = Array.foldBack extractUsefulOptionsAndSources projOpts ([], []) { ProjectFile = projFile SourceFiles = sourceFiles diff --git a/src/Fable.Cli/Util.fs b/src/Fable.Cli/Util.fs index c7a9c52e8d..27498a8110 100644 --- a/src/Fable.Cli/Util.fs +++ b/src/Fable.Cli/Util.fs @@ -248,6 +248,11 @@ module File = let isDirectoryEmpty dir = not(Directory.Exists(dir)) || Directory.EnumerateFileSystemEntries(dir) |> Seq.isEmpty + let safeDelete path = + try + File.Delete(path) + with _ -> () + let withLock (dir: string) (action: unit -> 'T) = let mutable fileCreated = false let lockFile = Path.Join(dir, "fable.lock") diff --git a/src/Fable.Transforms/Fable.Transforms.fsproj b/src/Fable.Transforms/Fable.Transforms.fsproj index 686c030764..09a8e7c96d 100644 --- a/src/Fable.Transforms/Fable.Transforms.fsproj +++ b/src/Fable.Transforms/Fable.Transforms.fsproj @@ -3,6 +3,7 @@ true netstandard2.0 + $(OtherFlags) --nowarn:3536 From 90f458437bfc1cdab699600cd89d217edc198e16 Mon Sep 17 00:00:00 2001 From: Alfonso Garcia-Caro Date: Sat, 12 Nov 2022 18:28:33 +0900 Subject: [PATCH 2/3] Try to fix Python build --- src/Fable.Cli/Main.fs | 3 +++ src/Fable.Cli/ProjectCracker.fs | 1 - src/fable-library-py/fable_library/Fable.Library.fsproj | 1 + tests/Python/Fable.Tests.Python.fsproj | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Fable.Cli/Main.fs b/src/Fable.Cli/Main.fs index d5ff3aaea4..80039e617f 100644 --- a/src/Fable.Cli/Main.fs +++ b/src/Fable.Cli/Main.fs @@ -343,6 +343,9 @@ type ProjectCracked(cliArgs: CliArgs, crackerResponse: CrackerResponse, sourceFi // We display "parsed" because "cracked" may not be understood by users Log.always $"Project and references ({result.ProjectOptions.SourceFiles.Length} source files) parsed in %i{ms}ms{Log.newLine}" Log.verbose(lazy $"""F# PROJECT: %s{cliArgs.ProjectFileAsRelativePath} +FABLE LIBRARY: {result.FableLibDir} +OUTPUT TYPE: {result.OutputType} + %s{result.ProjectOptions.OtherOptions |> String.concat $"{Log.newLine} "} %s{result.ProjectOptions.SourceFiles |> String.concat $"{Log.newLine} "}{Log.newLine}""") diff --git a/src/Fable.Cli/ProjectCracker.fs b/src/Fable.Cli/ProjectCracker.fs index 9f74a2ea35..361e1fec96 100644 --- a/src/Fable.Cli/ProjectCracker.fs +++ b/src/Fable.Cli/ProjectCracker.fs @@ -597,7 +597,6 @@ let getFableLibraryPath (opts: CrackerOptions) = |> File.tryFindNonEmptyDirectoryUpwards {| matches = [buildDir; "build/" + buildDir]; exclude = ["src"] |} |> Option.defaultWith (fun () -> Fable.FableError "Cannot find fable-library" |> raise) - Log.verbose(lazy ("fable-library: " + fableLibrarySource)) let fableLibraryTarget = IO.Path.Combine(opts.FableModulesDir, libDir) // Always overwrite fable-library in case it has been updated, see #3208 copyDir false fableLibrarySource fableLibraryTarget diff --git a/src/fable-library-py/fable_library/Fable.Library.fsproj b/src/fable-library-py/fable_library/Fable.Library.fsproj index ed88d7f179..0ed8766140 100644 --- a/src/fable-library-py/fable_library/Fable.Library.fsproj +++ b/src/fable-library-py/fable_library/Fable.Library.fsproj @@ -1,6 +1,7 @@  + Library netstandard2.0 $(DefineConstants);FABLE_COMPILER $(DefineConstants);FX_NO_BIGINT diff --git a/tests/Python/Fable.Tests.Python.fsproj b/tests/Python/Fable.Tests.Python.fsproj index aa77fee5ec..f31f53f258 100644 --- a/tests/Python/Fable.Tests.Python.fsproj +++ b/tests/Python/Fable.Tests.Python.fsproj @@ -1,5 +1,6 @@ + Exe net6.0 false false From e6c040da650fc7abdc010d6fafe040fbbb88016a Mon Sep 17 00:00:00 2001 From: Alfonso Garcia-Caro Date: Sat, 12 Nov 2022 23:06:02 +0900 Subject: [PATCH 3/3] Use Output.Exe as default when targeting Python --- src/Fable.Cli/Main.fs | 19 ++++++----- src/Fable.Cli/Pipeline.fs | 3 +- src/Fable.Cli/ProjectCracker.fs | 43 ++++++++++++++----------- src/Fable.Cli/Util.fs | 12 +++++-- src/Fable.Transforms/Global/Compiler.fs | 2 -- src/Fable.Transforms/State.fs | 15 +++------ 6 files changed, 49 insertions(+), 45 deletions(-) diff --git a/src/Fable.Cli/Main.fs b/src/Fable.Cli/Main.fs index 80039e617f..31620806b6 100644 --- a/src/Fable.Cli/Main.fs +++ b/src/Fable.Cli/Main.fs @@ -320,16 +320,8 @@ type ProjectCracked(cliArgs: CliArgs, crackerResponse: CrackerResponse, sourceFi let fableLibDir = Path.getRelativePath currentFile crackerResponse.FableLibDir let watchDependencies = if cliArgs.IsWatch then Some(HashSet()) else None - let common = Path.getCommonBaseDir([currentFile; crackerResponse.FableLibDir]) - let outputType = - // Everything within the Fable hidden directory will be compiled as Library. We do this since the files there will be - // compiled as part of the main project which might be a program (Exe) or library (Library). - if common.EndsWith(Naming.fableModules) then - Some "Library" - else - crackerResponse.OutputType - - CompilerImpl(currentFile, project, opts, fableLibDir, ?watchDependencies=watchDependencies, ?outDir=cliArgs.OutDir, ?outType=outputType) + CompilerImpl(currentFile, project, opts, fableLibDir, crackerResponse.OutputType, + ?outDir=cliArgs.OutDir, ?watchDependencies=watchDependencies) member _.MapSourceFiles(f) = ProjectCracked(cliArgs, crackerResponse, Array.map f sourceFiles) @@ -349,6 +341,13 @@ OUTPUT TYPE: {result.OutputType} %s{result.ProjectOptions.OtherOptions |> String.concat $"{Log.newLine} "} %s{result.ProjectOptions.SourceFiles |> String.concat $"{Log.newLine} "}{Log.newLine}""") + // If targeting Python, make sure users are not compiling the project as library by mistake + // (imports won't work when running the code) + match cliArgs.CompilerOptions.Language, result.OutputType with + | Python, OutputType.Library -> + Log.always "Compiling project as Library. If you intend to run the code directly, please set OutputType to Exe." + | _ -> () + let sourceFiles = result.ProjectOptions.SourceFiles |> Array.map File ProjectCracked(cliArgs, result, sourceFiles) diff --git a/src/Fable.Cli/Pipeline.fs b/src/Fable.Cli/Pipeline.fs index b65d203b1f..838afe0aa9 100644 --- a/src/Fable.Cli/Pipeline.fs +++ b/src/Fable.Cli/Pipeline.fs @@ -153,7 +153,8 @@ module Python = | Some Py.Naming.sitePackages -> true | _ -> false - + // Everything within the Fable hidden directory will be compiled as Library. We do this since the files there will be + // compiled as part of the main project which might be a program (Exe) or library (Library). let isLibrary = com.OutputType = OutputType.Library || Naming.isInFableModules com.CurrentFile let isFableLibrary = isLibrary && List.contains "FABLE_LIBRARY" com.Options.Define diff --git a/src/Fable.Cli/ProjectCracker.fs b/src/Fable.Cli/ProjectCracker.fs index 361e1fec96..638c99f03e 100644 --- a/src/Fable.Cli/ProjectCracker.fs +++ b/src/Fable.Cli/ProjectCracker.fs @@ -12,8 +12,6 @@ open Fable.AST open Globbing.Operators open Buildalyzer -let [] TARGET_FRAMEWORK = "net6.0" - type FablePackage = { Id: string Version: string @@ -33,7 +31,7 @@ type CacheInfo = OutDir: string option FableLibDir: string FableModulesDir: string - OutputType: string option + OutputType: OutputType Exclude: string list SourceMaps: bool SourceMapsRoot: string option @@ -61,8 +59,13 @@ type CacheInfo = | Some other -> this.GetTimestamp() > other.GetTimestamp() type CrackerOptions(cliArgs: CliArgs) = + let projDir = IO.Path.GetDirectoryName cliArgs.ProjectFile + let targetFramework = + match Process.runSyncWithOutput projDir "dotnet" ["--version"] with + | Naming.StartsWith "7" _ -> "net7.0" + | _ -> "net6.0" + let fableModulesDir = CrackerOptions.GetFableModulesFromProject(projDir, cliArgs.OutDir, cliArgs.NoCache) let builtDlls = HashSet() - let fableModulesDir = CrackerOptions.GetFableModulesFromProject(cliArgs.ProjectFile, cliArgs.OutDir, cliArgs.NoCache) let cacheInfo = if cliArgs.NoCache then None else CacheInfo.TryRead(fableModulesDir, cliArgs.CompilerOptions.DebugMode) @@ -74,6 +77,7 @@ type CrackerOptions(cliArgs: CliArgs) = member _.FableLib: string option = cliArgs.FableLibraryPath member _.OutDir: string option = cliArgs.OutDir member _.Configuration: string = cliArgs.Configuration + member _.TargetFramework = targetFramework member _.Exclude: string list = cliArgs.Exclude member _.Replace: Map = cliArgs.Replace member _.PrecompiledLib: string option = cliArgs.PrecompiledLib @@ -98,10 +102,10 @@ type CrackerOptions(cliArgs: CliArgs) = IO.Path.Combine(baseDir, Naming.fableModules) |> Path.normalizePath - static member GetFableModulesFromProject(projFile: string, outDir: string option, noCache: bool): string = + static member GetFableModulesFromProject(projDir: string, outDir: string option, noCache: bool): string = let fableModulesDir = outDir - |> Option.defaultWith (fun () -> IO.Path.GetDirectoryName(projFile)) + |> Option.defaultWith (fun () -> projDir) |> CrackerOptions.GetFableModulesFromDir if noCache then @@ -120,7 +124,7 @@ type CrackerResponse = FableModulesDir: string References: string list ProjectOptions: FSharpProjectOptions - OutputType: string option + OutputType: OutputType PrecompiledInfo: PrecompiledInfoImpl option CanReuseCompiledFiles: bool } @@ -320,6 +324,8 @@ let private extractUsefulOptionsAndSources (line: string) (accSources: string li if line.StartsWith("--nowarn") || line.StartsWith("--warnon") then accSources, line::accOptions elif line.StartsWith("--define:") then + // When parsing the project as .csproj there will be multiple defines in the same line, + // but the F# compiler seems to accept only one per line let defines = line.Substring(9).Split(';') |> Array.mapToList (fun d -> "--define:" + d) accSources, defines @ accOptions else @@ -409,7 +415,7 @@ let getProjectOptionsFromProjectFile = let options = AnalyzerManagerOptions(LogWriter = log) let m = AnalyzerManager(options) m.SetGlobalProperty("Configuration", opts.Configuration) - m.SetGlobalProperty("TargetFramework", TARGET_FRAMEWORK) + m.SetGlobalProperty("TargetFramework", opts.TargetFramework) for define in opts.FableOptions.Define do m.SetGlobalProperty(define, "true") manager <- Some m @@ -428,6 +434,8 @@ let getProjectOptionsFromProjectFile = ProjectReferences = result.ProjectReferences Properties = result.Properties |}) + // Because Buildalyzer works better with .csproj, we first "dress up" the project as if it were a C# one + // and try to adapt the results. If it doesn't work, we try again to analyze the .fsproj directly let csprojResult = let csprojFile = projFile.Replace(".fsproj", ".csproj") if IO.File.Exists(csprojFile) then @@ -435,7 +443,7 @@ let getProjectOptionsFromProjectFile = else try System.IO.File.Copy(projFile, csprojFile) - projFile.Replace(".fsproj", ".csproj") + csprojFile |> tryGetResult (fun r -> // Careful, options for .csproj start with / but so do root paths in unix let reg = System.Text.RegularExpressions.Regex(@"^\/[^\/]+?(:?:|$)") @@ -478,7 +486,7 @@ let fullCrack (opts: CrackerOptions): CrackedFsproj = Process.runSync (IO.Path.GetDirectoryName opts.ProjFile) "dotnet" [ "restore" IO.Path.GetFileName opts.ProjFile - $"-p:TargetFramework={TARGET_FRAMEWORK}" + $"-p:TargetFramework={opts.TargetFramework}" for constant in opts.FableOptions.Define do $"-p:{constant}=true" ] |> ignore @@ -486,14 +494,8 @@ let fullCrack (opts: CrackerOptions): CrackedFsproj = let projOpts, projRefs, msbuildProps = getProjectOptionsFromProjectFile opts opts.ProjFile - // let targetFramework = - // match Map.tryFind "TargetFramework" msbuildProps with - // | Some targetFramework -> targetFramework - // | None -> failwithf "Cannot find TargetFramework for project %s" projFile - - let outputType = ReadOnlyDictionary.tryFind "OutputType" msbuildProps - - getCrackedFsproj opts projOpts projRefs outputType + ReadOnlyDictionary.tryFind "OutputType" msbuildProps + |> getCrackedFsproj opts projOpts projRefs /// For project references of main project, ignore dll and package references let easyCrack (opts: CrackerOptions) dllRefs (projFile: string): CrackedFsproj = @@ -818,9 +820,12 @@ let getFullProjectOpts (opts: CrackerOptions) = else Some("-r:" + r)) |> Seq.toArray - let outputType = mainProj.OutputType let projRefs = projRefs |> List.map (fun p -> p.ProjectFile) let otherOptions = Array.append otherOptions dllRefs + let outputType = + match mainProj.OutputType with + | Some "Library" -> OutputType.Library + | _ -> OutputType.Exe let cacheInfo: CacheInfo = { diff --git a/src/Fable.Cli/Util.fs b/src/Fable.Cli/Util.fs index 27498a8110..090434aaba 100644 --- a/src/Fable.Cli/Util.fs +++ b/src/Fable.Cli/Util.fs @@ -334,7 +334,7 @@ module Process = IO.Path.GetFullPath(dir) + (if isWindows() then ";" else ":") + currentPath // Adapted from https://github.com/enricosada/dotnet-proj-info/blob/1e6d0521f7f333df7eff3148465f7df6191e0201/src/dotnet-proj/Program.fs#L155 - let private startProcess (envVars: (string * string) list) workingDir exePath (args: string list) = + let private startProcess redirectOutput (envVars: (string * string) list) workingDir exePath (args: string list) = let exePath, args = if isWindows() then "cmd", "/C"::exePath::args else exePath, args @@ -351,6 +351,7 @@ module Process = psi.WorkingDirectory <- workingDir psi.CreateNoWindow <- false psi.UseShellExecute <- false + psi.RedirectStandardOutput <- redirectOutput // TODO: Make this output no logs if we've set silent verbosity Process.Start(psi) @@ -377,7 +378,7 @@ module Process = fun (workingDir: string) (exePath: string) (args: string list) -> try runningProcess |> Option.iter kill - let p = startProcess envVars workingDir exePath args + let p = startProcess false envVars workingDir exePath args runningProcess <- Some p with ex -> Log.always("Cannot run: " + ex.Message) @@ -387,7 +388,7 @@ module Process = let runSyncWithEnv envVars (workingDir: string) (exePath: string) (args: string list) = try - let p = startProcess envVars workingDir exePath args + let p = startProcess false envVars workingDir exePath args p.WaitForExit() p.ExitCode with ex -> @@ -398,6 +399,11 @@ module Process = let runSync (workingDir: string) (exePath: string) (args: string list) = runSyncWithEnv [] workingDir exePath args + let runSyncWithOutput workingDir exePath args = + let p = startProcess true [] workingDir exePath args + p.WaitForExit() + p.StandardOutput.ReadToEnd() + [] module Async = let fold f (state: 'State) (xs: 'T seq) = async { diff --git a/src/Fable.Transforms/Global/Compiler.fs b/src/Fable.Transforms/Global/Compiler.fs index b8e0245387..7598faa87d 100644 --- a/src/Fable.Transforms/Global/Compiler.fs +++ b/src/Fable.Transforms/Global/Compiler.fs @@ -36,8 +36,6 @@ type Severity = type OutputType = | Library | Exe - | Module - | Winexe open FSharp.Compiler.Symbols open Fable.AST diff --git a/src/Fable.Transforms/State.fs b/src/Fable.Transforms/State.fs index dc71892c6f..78f6e0155c 100644 --- a/src/Fable.Transforms/State.fs +++ b/src/Fable.Transforms/State.fs @@ -176,17 +176,12 @@ type Log = /// Type with utilities for compiling F# files to JS. /// Not thread-safe, an instance must be created per file -type CompilerImpl(currentFile, project: Project, options, fableLibraryDir: string, ?outDir: string, ?outType: string, +type CompilerImpl(currentFile, project: Project, options, fableLibDir: string, ?outType: OutputType, ?outDir: string, ?watchDependencies: HashSet, ?logs: ResizeArray, ?isPrecompilingInlineFunction: bool) = + let outType = defaultArg outType OutputType.Exe let logs = Option.defaultWith ResizeArray logs - let fableLibraryDir = fableLibraryDir.TrimEnd('/') - let outputType = - match outType with - | Some "Exe" -> OutputType.Exe - | Some "Module" -> OutputType.Module - | Some "Winexe" -> OutputType.Winexe - | _ -> OutputType.Library + let fableLibraryDir = fableLibDir.TrimEnd('/') member _.Logs = logs.ToArray() member _.WatchDependencies = @@ -198,7 +193,7 @@ type CompilerImpl(currentFile, project: Project, options, fableLibraryDir: strin member _.LibraryDir = fableLibraryDir member _.CurrentFile = currentFile member _.OutputDir = outDir - member _.OutputType = outputType + member _.OutputType = outType member _.ProjectFile = project.ProjectFile member _.SourceFiles = project.SourceFiles @@ -211,7 +206,7 @@ type CompilerImpl(currentFile, project: Project, options, fableLibraryDir: strin Path.Combine(Path.GetDirectoryName(currentFile), fableLibraryDir) else fableLibraryDir |> Path.getRelativeFileOrDirPath false file true - CompilerImpl(file, project, options, fableLibraryDir, ?outDir=outDir, ?outType=outType, + CompilerImpl(file, project, options, fableLibraryDir, outType, ?outDir=outDir, ?watchDependencies=watchDependencies, logs=logs, isPrecompilingInlineFunction=true) member _.GetImplementationFile(fileName) =