Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified lib/fcs/FSharp.Compiler.Service.dll
Binary file not shown.
Binary file modified lib/fcs/FSharp.Core.dll
Binary file not shown.
1 change: 1 addition & 0 deletions src/Fable.Cli/Entry.fs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ type Runner =
RootDir = rootDir
Configuration = configuration
OutDir = outDir
IsWatch = watch
Precompile = precompile
PrecompiledLib = precompiledLib
SourceMaps = args.FlagEnabled "-s" || args.FlagEnabled "--sourceMaps"
Expand Down
425 changes: 246 additions & 179 deletions src/Fable.Cli/Main.fs

Large diffs are not rendered by default.

23 changes: 13 additions & 10 deletions src/Fable.Cli/ProjectCracker.fs
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,24 @@ type CacheInfo =
FableLibDir: string
Timestamp: DateTime
}
static member GetPath(fableModulesPath: string) =
IO.Path.Combine(fableModulesPath, "cache_info.json")
static member GetPath(fableModulesPath: string, isDebug: bool) =
IO.Path.Combine(fableModulesPath, $"""project_cracked{if isDebug then "_debug" else ""}.json""")

static member TryRead(fableModulesPath: string): CacheInfo option =
static member TryRead(fableModulesPath: string, isDebug): CacheInfo option =
try
CacheInfo.GetPath(fableModulesPath) |> Json.read<CacheInfo> |> Some
CacheInfo.GetPath(fableModulesPath, isDebug) |> Json.read<CacheInfo> |> Some
with _ -> None

member this.Write(fableModulesPath: string) =
let path = CacheInfo.GetPath(fableModulesPath)
member this.Write(fableModulesPath: string, isDebug) =
let path = CacheInfo.GetPath(fableModulesPath, isDebug)
Json.write path this

type CrackerOptions(fableOpts, fableLib, outDir, configuration, exclude, replace, precompiledLib, noCache, noRestore, projFile) =
type CrackerOptions(fableOpts: CompilerOptions, fableLib, outDir, configuration, exclude, replace, precompiledLib, noCache, noRestore, projFile) =
let builtDlls = HashSet()
let fableModulesDir = CrackerOptions.GetFableModulesDir(projFile, outDir)
let cacheInfo =
if noCache then None
else CacheInfo.TryRead(fableModulesDir)
else CacheInfo.TryRead(fableModulesDir, fableOpts.DebugMode)

member _.CacheInfo = cacheInfo
member _.FableModulesDir = fableModulesDir
Expand All @@ -71,7 +71,7 @@ type CrackerOptions(fableOpts, fableLib, outDir, configuration, exclude, replace
Process.runSync projDir "dotnet" ["build"; "-c"; configuration] |> ignore
builtDlls.Add(normalizedDllPath) |> ignore

static member GetFableModulesDir(projFile: string, outDir: string option) =
static member GetFableModulesDir(projFile: string, outDir: string option): string =
let fableModulesDir =
let baseDir = outDir |> Option.defaultWith (fun () -> IO.Path.GetDirectoryName(projFile))
IO.Path.Combine(baseDir, Naming.fableModules)
Expand All @@ -84,6 +84,7 @@ type CrackerOptions(fableOpts, fableLib, outDir, configuration, exclude, replace

type CrackerResponse =
{ FableLibDir: string
FableModulesDir: string
References: string list
ProjectOptions: FSharpProjectOptions
PrecompiledInfo: PrecompiledInfoImpl option
Expand Down Expand Up @@ -622,6 +623,7 @@ let getFullProjectOpts (opts: CrackerOptions) =
{ ProjectOptions = makeProjectOptions opts.ProjFile otherOptions sourcePaths
References = cacheInfo.References
FableLibDir = cacheInfo.FableLibDir
FableModulesDir = opts.FableModulesDir
PrecompiledInfo = precompiledInfo
CacheInvalidated = false }

Expand Down Expand Up @@ -696,10 +698,11 @@ let getFullProjectOpts (opts: CrackerOptions) =
Timestamp = DateTime.Now
}

cacheInfo.Write(opts.FableModulesDir)
cacheInfo.Write(opts.FableModulesDir, opts.FableOptions.DebugMode)

{ ProjectOptions = makeProjectOptions opts.ProjFile otherOptions sourcePaths
References = projRefs
FableLibDir = fableLibDir
FableModulesDir = opts.FableModulesDir
PrecompiledInfo = precompiledInfo
CacheInvalidated = true }
38 changes: 26 additions & 12 deletions src/Fable.Cli/Util.fs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type CliArgs =
{ ProjectFile: string
RootDir: string
OutDir: string option
IsWatch: bool
Precompile: bool
PrecompiledLib: string option
FableLibraryPath: string option
Expand Down Expand Up @@ -54,13 +55,27 @@ type Agent<'T> private (mbox: MailboxProcessor<'T>, cts: CancellationTokenSource
[<RequireQualifiedAccess>]
module Log =
let newLine = Environment.NewLine
let isCi = String.IsNullOrEmpty(Environment.GetEnvironmentVariable("CI")) |> not

let mutable private verbosity = Fable.Verbosity.Normal

/// To be called only at the beginning of the app
let makeVerbose() =
verbosity <- Fable.Verbosity.Verbose

let isVerbose() =
verbosity = Fable.Verbosity.Verbose

let inSameLineIfNotCI (msg: string) =
if not isCi then
let curCursorLeft = Console.CursorLeft
Console.SetCursorPosition(0, Console.CursorTop)
Console.Out.Write(msg)
let diff = curCursorLeft - msg.Length
if diff > 0 then
Console.Out.Write(String.replicate diff " ")
Console.SetCursorPosition(msg.Length, Console.CursorTop)

let alwaysWithColor color (msg: string) =
if verbosity <> Fable.Verbosity.Silent && not(String.IsNullOrEmpty(msg)) then
Console.ForegroundColor <- color
Expand Down Expand Up @@ -648,10 +663,10 @@ type PrecompiledInfoJson =
Files: Map<string, PrecompiledFileJson>
InlineExprHeaders: string[] }

type PrecompiledInfoImpl(dir: string, info: PrecompiledInfoJson) =
type PrecompiledInfoImpl(fableModulesDir: string, info: PrecompiledInfoJson) =
let dic = System.Collections.Concurrent.ConcurrentDictionary<int, Lazy<Map<string, Fable.InlineExpr>>>()
let comparer = StringOrdinalComparer()
let dllPath = PrecompiledInfoImpl.GetDllPath(dir)
let dllPath = PrecompiledInfoImpl.GetDllPath(fableModulesDir)

member _.CompilerVersion = info.CompilerVersion
member _.CompilerOptions = info.CompilerOptions
Expand All @@ -663,8 +678,8 @@ type PrecompiledInfoImpl(dir: string, info: PrecompiledInfoJson) =
Map.tryFind normalizedFullPath info.Files
|> Option.map (fun f -> f.OutPath)

static member GetDllPath(dir: string): string =
IO.Path.Combine(dir, Fable.Naming.fablePrecompile + ".dll")
static member GetDllPath(fableModulesDir: string): string =
IO.Path.Combine(fableModulesDir, Fable.Naming.fablePrecompile + ".dll")
|> Fable.Path.normalizeFullPath

interface Fable.Transforms.State.PrecompiledInfo with
Expand All @@ -681,16 +696,16 @@ type PrecompiledInfoImpl(dir: string, info: PrecompiledInfoJson) =
// http://reedcopsey.com/2011/01/16/concurrentdictionarytkeytvalue-used-with-lazyt/
let map = dic.GetOrAdd(index, fun _ ->
lazy
PrecompiledInfoImpl.GetInlineExprsPath(dir, index)
PrecompiledInfoImpl.GetInlineExprsPath(fableModulesDir, index)
|> Json.readWithStringPool<(string * Fable.InlineExpr)[]>
|> Map)
Map.tryFind memberUniqueName map.Value

static member GetPath(dir) =
IO.Path.Combine(dir, "precompiled_info.json")

static member GetInlineExprsPath(dir, index: int) =
IO.Path.Combine(dir, "inline_exprs", $"inline_exprs_{index}.json")
static member GetInlineExprsPath(fableModulesDir, index: int) =
IO.Path.Combine(fableModulesDir, "inline_exprs", $"inline_exprs_{index}.json")

static member Load(dir: string) =
try
Expand All @@ -700,8 +715,7 @@ type PrecompiledInfoImpl(dir: string, info: PrecompiledInfoJson) =
with
| e -> FableError($"Cannot load precompiled info from %s{dir}: %s{e.Message}") |> raise

static member Save(dllPath: string, files, inlineExprs, compilerOptions, fableLibDir) =
let dir = IO.Path.GetDirectoryName(dllPath)
static member Save(files, inlineExprs, compilerOptions, fableModulesDir, fableLibDir) =
let comparer = StringOrdinalComparer() :> System.Collections.Generic.IComparer<string>

let inlineExprs =
Expand All @@ -711,16 +725,16 @@ type PrecompiledInfoImpl(dir: string, info: PrecompiledInfoJson) =
|> Array.mapi (fun i chunk -> i, chunk)

do
PrecompiledInfoImpl.GetInlineExprsPath(dir, 0)
PrecompiledInfoImpl.GetInlineExprsPath(fableModulesDir, 0)
|> IO.Path.GetDirectoryName
|> IO.Directory.CreateDirectory
|> ignore

inlineExprs |> Array.Parallel.iter (fun (i, chunk) ->
let path = PrecompiledInfoImpl.GetInlineExprsPath(dir, i)
let path = PrecompiledInfoImpl.GetInlineExprsPath(fableModulesDir, i)
Json.writeWithStringPool path chunk)

let precompiledInfoPath = PrecompiledInfoImpl.GetPath(dir)
let precompiledInfoPath = PrecompiledInfoImpl.GetPath(fableModulesDir)
let inlineExprHeaders = inlineExprs |> Array.map (snd >> Array.head >> fst)

{ CompilerVersion = Fable.Literals.VERSION
Expand Down
20 changes: 10 additions & 10 deletions src/Fable.Transforms/FSharp2Fable.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1427,7 +1427,7 @@ let rec private transformDeclarations (com: FableCompiler) ctx fsDecls =
{ Body = e
UsedNames = set ctx.UsedNamesInDeclarationScope }])

let getRootFSharpEntities (file: FSharpImplementationFileContents) =
let rec getRootFSharpEntities (declarations: FSharpImplementationFileDeclaration list) =
let rec getRootFSharpEntitiesInner decl = seq {
match decl with
| FSharpImplementationFileDeclaration.Entity (ent, nested) ->
Expand All @@ -1437,9 +1437,9 @@ let getRootFSharpEntities (file: FSharpImplementationFileContents) =
else ent
| _ -> ()
}
file.Declarations |> Seq.collect getRootFSharpEntitiesInner
Seq.collect getRootFSharpEntitiesInner declarations

let getRootModule (file: FSharpImplementationFileContents) =
let getRootModule (declarations: FSharpImplementationFileDeclaration list) =
let rec getRootModuleInner outerEnt decls =
match decls, outerEnt with
| [FSharpImplementationFileDeclaration.Entity (ent, decls)], _ when ent.IsFSharpModule || ent.IsNamespace ->
Expand All @@ -1448,7 +1448,7 @@ let getRootModule (file: FSharpImplementationFileContents) =
getRootModuleInner (Some ent) decls
| _, Some e -> FsEnt.FullName e
| _, None -> ""
getRootModuleInner None file.Declarations
getRootModuleInner None declarations

type FableCompiler(com: Compiler) =
let attachedMembers = Dictionary<string, _>()
Expand Down Expand Up @@ -1639,7 +1639,7 @@ type FableCompiler(com: Compiler) =
member _.AddLog(msg, severity, ?range, ?fileName:string, ?tag: string) =
com.AddLog(msg, severity, ?range=range, ?fileName=fileName, ?tag=tag)

let getInlineExprs (file: FSharpImplementationFileContents) =
let getInlineExprs fileName (declarations: FSharpImplementationFileDeclaration list) =

let rec getInlineExprsInner decls =
decls |> List.collect (function
Expand All @@ -1660,23 +1660,23 @@ let getInlineExprs (file: FSharpImplementationFileContents) =

{ Args = List.rev idents
Body = com.Transform(ctx, body)
FileName = file.FileName
FileName = fileName
ScopeIdents = set ctx.UsedNamesInDeclarationScope })

[getMemberUniqueName memb, inlineExpr]

| FSharpImplementationFileDeclaration.MemberOrFunctionOrValue _
| FSharpImplementationFileDeclaration.InitAction _ -> []
)
getInlineExprsInner file.Declarations
getInlineExprsInner declarations

let transformFile (com: Compiler) =
let file = com.GetImplementationFile(com.CurrentFile)
let usedRootNames = getUsedRootNames com Set.empty file.Declarations
let declarations = com.GetImplementationFile(com.CurrentFile)
let usedRootNames = getUsedRootNames com Set.empty declarations
let ctx = Context.Create(usedRootNames)
let com = FableCompiler(com)
let rootDecls =
transformDeclarations com ctx file.Declarations
transformDeclarations com ctx declarations
|> List.map (function
| Fable.ClassDeclaration decl as classDecl ->
com.TryGetAttachedMembers(decl.Entity.FullName)
Expand Down
7 changes: 2 additions & 5 deletions src/Fable.Transforms/Global/Compiler.fs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ type Compiler =
abstract ProjectFile: string
abstract Options: CompilerOptions
abstract Plugins: CompilerPlugins
abstract GetImplementationFile: fileName: string -> FSharpImplementationFileContents
abstract GetImplementationFile: fileName: string -> FSharpImplementationFileDeclaration list
abstract GetRootModule: fileName: string -> string
abstract TryGetEntity: Fable.EntityRef -> Fable.Entity option
abstract GetInlineExpr: string -> InlineExpr
Expand All @@ -61,19 +61,16 @@ type Compiler =

type InlineExprLazy(f: Compiler -> InlineExpr) =
let mutable value: InlineExpr voption = ValueNone
member this.Force(com: Compiler) =
member this.Calculate(com: Compiler) =
lock this <| fun () ->
match value with
| ValueSome v -> v
| ValueNone ->
let v = f com
value <- ValueSome v
v

[<AutoOpen>]
module CompilerExt =
open System.Collections.Generic

let private expectedVersionMatchesActual (expected: string) (actual: string) =
try
let r = System.Text.RegularExpressions.Regex(@"^(\d+)\.(\d+)(?:\.(\d+))?")
Expand Down
6 changes: 4 additions & 2 deletions src/Fable.Transforms/Global/Prelude.fs
Original file line number Diff line number Diff line change
Expand Up @@ -504,12 +504,14 @@ module Path =
normalizePath (GetFullPath path)

/// If path belongs to a signature file (.fsi), replace the extension with .fs
let normalizePathAndEnsureFsExtension (path: string) =
let path = normalizePath path
let ensureFsExtension (path: string) =
if path.EndsWith(".fsi")
then path.Substring(0, path.Length - 1)
else path

let normalizePathAndEnsureFsExtension (path: string) =
normalizePath path |> ensureFsExtension

let replaceExtension (newExt: string) (path: string) =
let i = path.LastIndexOf(".")
if i > 0 then path.Substring(0, i) + newExt
Expand Down
42 changes: 20 additions & 22 deletions src/Fable.Transforms/State.fs
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,13 @@ type Assemblies(getPlugin, fsharpAssemblies: FSharpAssembly list) =

type ImplFile =
{
Ast: FSharpImplementationFileContents
Declarations: FSharpImplementationFileDeclaration list
RootModule: string
Entities: IReadOnlyDictionary<string, Fable.Entity>
InlineExprs: (string * InlineExprLazy) list
}
static member From(file: FSharpImplementationFileContents) =
let declarations = file.Declarations
let entities = Dictionary()
let rec loop (ents: FSharpEntity seq) =
for e in ents do
Expand All @@ -93,12 +94,12 @@ type ImplFile =
entities.Add(fableEnt.FullName, fableEnt)
loop e.NestedEntities

FSharp2Fable.Compiler.getRootFSharpEntities file |> loop
FSharp2Fable.Compiler.getRootFSharpEntities declarations |> loop
{
Ast = file
Declarations = file.Declarations
Entities = entities
RootModule = FSharp2Fable.Compiler.getRootModule file
InlineExprs = FSharp2Fable.Compiler.getInlineExprs file
RootModule = FSharp2Fable.Compiler.getRootModule declarations
InlineExprs = FSharp2Fable.Compiler.getInlineExprs file.FileName declarations
}

type PrecompiledInfo =
Expand All @@ -124,7 +125,7 @@ type Project(projFile: string,
member _.TryGetRootModule(_) = None
member _.TryGetInlineExpr(_) = None })

static member From(projFile,
static member From(projFile: string,
fsharpFiles: FSharpImplementationFileContents list,
fsharpAssemblies: FSharpAssembly list,
?getPlugin: PluginRef -> System.Type,
Expand All @@ -143,27 +144,24 @@ type Project(projFile: string,

Project(projFile, implFilesMap, assemblies, ?precompiledInfo=precompiledInfo)

member this.Update(fsharpFiles: FSharpImplementationFileContents list) =
member this.Update(file: FSharpImplementationFileContents) =
let implFiles =
(this.ImplementationFiles, fsharpFiles) ||> List.fold (fun implFiles file ->
let key = Path.normalizePathAndEnsureFsExtension file.FileName
let file = ImplFile.From(file)
Map.add key file implFiles)

let key = Path.normalizePathAndEnsureFsExtension file.FileName
let file = ImplFile.From(file)
Map.add key file this.ImplementationFiles
Project(this.ProjectFile, implFiles, this.Assemblies, this.PrecompiledInfo)

member _.TryGetInlineExpr(com: Compiler, memberUniqueName: string) =
inlineExprsDic.TryValue(memberUniqueName)
|> Option.map (fun e -> e.Force(com))
|> Option.map (fun e -> e.Calculate(com))

member _.GetAllInlineExprs(com: Compiler): (string * InlineExpr)[] =
implFiles
|> Map.values
|> Seq.map (fun f -> f.InlineExprs)
|> Seq.toArray
|> Array.Parallel.map (List.mapToArray (fun (uniqueName, expr) ->
uniqueName, expr.Force(com)))
|> Array.concat
member _.GetFileInlineExprs(com: Compiler): (string * InlineExpr)[] =
match Map.tryFind com.CurrentFile implFiles with
| None -> [||]
| Some implFile ->
implFile.InlineExprs
|> List.mapToArray (fun (uniqueName, expr) ->
uniqueName, expr.Calculate(com))

member _.ProjectFile = projFile
member _.ImplementationFiles = implFiles
Expand Down Expand Up @@ -212,7 +210,7 @@ type CompilerImpl(currentFile, project: Project, options, fableLibraryDir: strin
member _.GetImplementationFile(fileName) =
let fileName = Path.normalizePathAndEnsureFsExtension fileName
match Map.tryFind fileName project.ImplementationFiles with
| Some file -> file.Ast
| Some file -> file.Declarations
| None -> failwith ("Cannot find implementation file " + fileName)

member this.GetRootModule(fileName) =
Expand Down
Loading