diff --git a/Fable.sln b/Fable.sln
index 8adccb6e07..b9aba20c23 100644
--- a/Fable.sln
+++ b/Fable.sln
@@ -62,6 +62,8 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Fable.Tests.Spaces", "tests
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Fable.Build", "src\Fable.Build\Fable.Build.fsproj", "{F2E323CE-FDF3-4A1E-AE97-B723D2E63763}"
EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Fable.Compiler", "src\Fable.Compiler\Fable.Compiler.fsproj", "{942DD29B-07C0-4ACF-891E-85C1235A9BE0}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -160,6 +162,10 @@ Global
{F2E323CE-FDF3-4A1E-AE97-B723D2E63763}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F2E323CE-FDF3-4A1E-AE97-B723D2E63763}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F2E323CE-FDF3-4A1E-AE97-B723D2E63763}.Release|Any CPU.Build.0 = Release|Any CPU
+ {942DD29B-07C0-4ACF-891E-85C1235A9BE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {942DD29B-07C0-4ACF-891E-85C1235A9BE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {942DD29B-07C0-4ACF-891E-85C1235A9BE0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {942DD29B-07C0-4ACF-891E-85C1235A9BE0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -189,6 +195,7 @@ Global
{F9134F40-C6CD-4368-A28E-33E5102FD4AB} = {CF0A8EC3-841F-4A54-B9FC-8D174CCD4A90}
{C90E23AF-4B5B-44A7-ADCC-3BF89547395B} = {DA29278E-3808-42DE-8333-964F129F295D}
{F2E323CE-FDF3-4A1E-AE97-B723D2E63763} = {C8CB96CF-68A8-4083-A0F8-319275CF8097}
+ {942DD29B-07C0-4ACF-891E-85C1235A9BE0} = {C8CB96CF-68A8-4083-A0F8-319275CF8097}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {58DF9285-8523-4EAC-B598-BE5B02A76A00}
diff --git a/src/Fable.Build/Publish.fs b/src/Fable.Build/Publish.fs
index 8f8826898f..ff4862d52a 100644
--- a/src/Fable.Build/Publish.fs
+++ b/src/Fable.Build/Publish.fs
@@ -155,6 +155,7 @@ let handle (args: string list) =
publishNuget ProjectDir.fableAst
publishNuget ProjectDir.fableCore
+ publishNuget ProjectDir.fableCompiler
publishNuget ProjectDir.fableCli
publishNuget ProjectDir.fablePublishUtils
diff --git a/src/Fable.Build/Workspace.fs b/src/Fable.Build/Workspace.fs
index f7f64fa316..bc7179391a 100644
--- a/src/Fable.Build/Workspace.fs
+++ b/src/Fable.Build/Workspace.fs
@@ -11,6 +11,7 @@ module ProjectDir =
let fableCore = Path.Resolve("src", "Fable.Core")
let fableCli = Path.Resolve("src", "Fable.Cli")
let fablePublishUtils = Path.Resolve("src", "Fable.PublishUtils")
+ let fableCompiler = Path.Resolve("src", "Fable.Compiler")
let temp_fable_library = Path.Resolve("temp", "fable-library")
let fable_library = Path.Resolve("src", "fable-library")
let fable_metadata = Path.Resolve("src", "fable-metadata")
diff --git a/src/Fable.Cli/Entry.fs b/src/Fable.Cli/Entry.fs
index d9394f949a..1d3b6c1f29 100644
--- a/src/Fable.Cli/Entry.fs
+++ b/src/Fable.Cli/Entry.fs
@@ -3,6 +3,7 @@ module Fable.Cli.Entry
open System
open Main
open Fable
+open Fable.Compiler.Util
type CliArgs(args: string list) =
let argsMap =
diff --git a/src/Fable.Cli/Fable.Cli.fsproj b/src/Fable.Cli/Fable.Cli.fsproj
index 8efee54df9..c0b1f736fd 100644
--- a/src/Fable.Cli/Fable.Cli.fsproj
+++ b/src/Fable.Cli/Fable.Cli.fsproj
@@ -50,11 +50,7 @@
-
-
-
-
@@ -65,6 +61,7 @@
+
diff --git a/src/Fable.Cli/FileWatchers.fs b/src/Fable.Cli/FileWatchers.fs
index ae951624b9..6bf99809d8 100644
--- a/src/Fable.Cli/FileWatchers.fs
+++ b/src/Fable.Cli/FileWatchers.fs
@@ -12,7 +12,7 @@ open System.Threading
open System.Collections.Generic
open System.Diagnostics
open System.Text.RegularExpressions
-open Fable.Cli.Globbing
+open Fable.Compiler.Globbing
type IFileSystemWatcher =
inherit IDisposable
diff --git a/src/Fable.Cli/Globbing.fs b/src/Fable.Cli/Globbing.fs
deleted file mode 100644
index 12ba2152d6..0000000000
--- a/src/Fable.Cli/Globbing.fs
+++ /dev/null
@@ -1,512 +0,0 @@
-namespace Fable.Cli
-
-open System
-open System.Collections.Generic
-open System.IO
-
-/// Globbing support and operators
-///
-/// Forked from `Fake.IO.FileSystem`
-module Globbing =
- /// This module contains a file pattern globbing implementation.
- []
- module Glob =
- open System
- open System.Text.RegularExpressions
-
- // Normalizes path for different OS
- let inline normalizePath (path: string) =
- path
- .Replace('\\', Path.DirectorySeparatorChar)
- .Replace('/', Path.DirectorySeparatorChar)
-
- type private SearchOption =
- | Directory of string
- | Drive of string
- | Recursive
- | FilePattern of string
-
- let private checkSubDirs absolute (dir: string) root =
- if dir.Contains "*" then
- try
- Directory.EnumerateDirectories(
- root,
- dir,
- SearchOption.TopDirectoryOnly
- )
- |> Seq.toList
- with :? System.IO.DirectoryNotFoundException ->
- List.empty
- else
- let path = Path.Combine(root, dir)
-
- let di =
- if absolute then
- new DirectoryInfo(dir)
- else
- new DirectoryInfo(path)
-
- if di.Exists then
- [ di.FullName ]
- else
- []
-
- let rec private buildPaths acc (input: SearchOption list) =
- match input with
- | [] -> acc
- | Directory name :: t ->
- let subDirs = List.collect (checkSubDirs false name) acc
- buildPaths subDirs t
- | Drive name :: t ->
- let subDirs = List.collect (checkSubDirs true name) acc
- buildPaths subDirs t
- | Recursive :: [] ->
- let dirs =
- Seq.collect
- (fun dir ->
- try
- Directory.EnumerateFileSystemEntries(
- dir,
- "*",
- SearchOption.AllDirectories
- )
- with :? System.IO.DirectoryNotFoundException ->
- Seq.empty
- )
- acc
-
- buildPaths (acc @ Seq.toList dirs) []
- | Recursive :: t ->
- let dirs =
- Seq.collect
- (fun dir ->
- try
- Directory.EnumerateDirectories(
- dir,
- "*",
- SearchOption.AllDirectories
- )
- with :? System.IO.DirectoryNotFoundException ->
- Seq.empty
- )
- acc
-
- buildPaths (acc @ Seq.toList dirs) t
- | FilePattern pattern :: _ ->
- acc
- |> List.collect (fun dir ->
- if Directory.Exists(Path.Combine(dir, pattern)) then
- [ Path.Combine(dir, pattern) ]
- else
- try
- Directory.EnumerateFiles(dir, pattern)
- |> Seq.toList
- with
- | :? System.IO.DirectoryNotFoundException
- | :? System.IO.PathTooLongException -> []
- )
-
- let private driveRegex = Regex(@"^[A-Za-z]:$", RegexOptions.Compiled)
-
- let inline private normalizeOutputPath (p: string) =
- p
- .Replace('\\', Path.DirectorySeparatorChar)
- .Replace('/', Path.DirectorySeparatorChar)
- .TrimEnd(Path.DirectorySeparatorChar)
-
- let internal getRoot (baseDirectory: string) (pattern: string) =
- let baseDirectory = normalizePath baseDirectory
- let normPattern = normalizePath pattern
-
- let patternParts =
- normPattern.Split(
- [|
- '/'
- '\\'
- |],
- StringSplitOptions.RemoveEmptyEntries
- )
-
- let patternPathParts =
- patternParts
- |> Seq.takeWhile (fun p -> not (p.Contains("*")))
- |> Seq.toArray
-
- let globRoot =
- // If we did not find any "*", then drop the last bit (it is a file name, not a pattern)
- (if patternPathParts.Length = patternParts.Length then
- patternPathParts.[0 .. patternPathParts.Length - 2]
- else
- patternPathParts)
- |> String.concat (Path.DirectorySeparatorChar.ToString())
-
- let globRoot =
- // If we dropped "/" from the beginning of the path in the 'Split' call, put it back!
- if normPattern.StartsWith('/') then
- "/" + globRoot
- else
- globRoot
-
- if Path.IsPathRooted globRoot then
- globRoot
- else
- Path.Combine(baseDirectory, globRoot)
-
- let internal search (baseDir: string) (originalInput: string) =
- let baseDir = normalizePath baseDir
- let input = normalizePath originalInput
-
- let input =
- if String.IsNullOrEmpty baseDir then
- input
- else
- // The final \ (or /) makes sure to only match complete folder
- // names (as one folder name could be a substring of the other)
- let start =
- baseDir.TrimEnd([| Path.DirectorySeparatorChar |])
- + string Path.DirectorySeparatorChar
- // See https://github.com/fsharp/FAKE/issues/1925
- if input.StartsWith(start, StringComparison.Ordinal) then
- input.Substring start.Length
- else
- input
-
- let filePattern = Path.GetFileName(input)
-
- let splits =
- input.Split(
- [|
- '/'
- '\\'
- |],
- StringSplitOptions.None
- )
-
- let baseItems =
- let start, rest =
- if
- input.StartsWith("\\\\", StringComparison.Ordinal)
- && splits.Length >= 4
- then
- let serverName = splits.[2]
- let share = splits.[3]
-
- [ Directory(sprintf "\\\\%s\\%s" serverName share) ],
- splits |> Seq.skip 4
- elif
- splits.Length >= 2
- && Path.IsPathRooted input
- && driveRegex.IsMatch splits.[0]
- then
- [ Directory(splits.[0] + "\\") ], splits |> Seq.skip 1
- elif
- splits.Length >= 2
- && Path.IsPathRooted input
- && input.StartsWith '/'
- then
- [ Directory("/") ], splits |> Array.toSeq
- else
- if Path.IsPathRooted input then
- if input.StartsWith '\\' then
- failwithf
- "Please remove the leading '\\' or '/' and replace them with \
- '.\\' or './' if you want to use a relative path. Leading \
- slashes are considered an absolute path (input was '%s')!"
- originalInput
- else
- failwithf
- "Unknown globbing input '%s', try to use a \
- relative path and report an issue!"
- originalInput
-
- [], splits |> Array.toSeq
-
- let restList =
- rest
- |> Seq.filter (String.IsNullOrEmpty >> not)
- |> Seq.map (
- function
- | "**" -> Recursive
- | a when a = filePattern -> FilePattern(a)
- | a -> Directory(a)
- )
- |> Seq.toList
-
- start @ restList
-
- baseItems |> buildPaths [ baseDir ] |> List.map normalizeOutputPath
-
- let internal compileGlobToRegex pattern =
- let pattern = normalizePath pattern
-
- let escapedPattern = (Regex.Escape pattern)
-
- let regexPattern =
- let xTOy =
- [
- "dirwildcard", (@"\\\*\\\*(/|\\\\)", @"(.*(/|\\))?")
- "stardotstar", (@"\\\*\\.\\\*", @"([^\\/]*)")
- "wildcard", (@"\\\*", @"([^\\/]*)")
- ]
- |> List.map (fun (key, (pattern, replace)) ->
- let pattern = sprintf "(?<%s>%s)" key pattern
- key, (pattern, replace)
- )
-
- let xTOyMap = xTOy |> Map.ofList
-
- let replacePattern =
- xTOy
- |> List.map (fun x -> x |> snd |> fst)
- |> String.concat ("|")
-
- let replaced =
- Regex(replacePattern)
- .Replace(
- escapedPattern,
- fun m ->
- let matched =
- xTOy
- |> Seq.map (fst)
- |> Seq.find (fun n ->
- m.Groups.Item(n).Success
- )
-
- (xTOyMap |> Map.tryFind matched).Value |> snd
- )
-
- "^" + replaced + "$"
-
- Regex(regexPattern)
-
- let private globRegexCache =
- System.Collections.Concurrent.ConcurrentDictionary()
-
- let isMatch pattern path : bool =
- let path = normalizePath path
-
- let regex =
- let outRegex: ref = ref null
-
- if globRegexCache.TryGetValue(pattern, outRegex) then
- outRegex.Value
- else
- let compiled = compileGlobToRegex pattern
- globRegexCache.TryAdd(pattern, compiled) |> ignore
- compiled
-
- regex.IsMatch(path)
-
- type IGlobbingPattern =
- inherit IEnumerable
- abstract BaseDirectory: string
- abstract Includes: string list
- abstract Excludes: string list
-
- type LazyGlobbingPattern =
- {
- BaseDirectory: string
- Includes: string list
- Excludes: string list
- }
-
- interface IGlobbingPattern with
- member this.BaseDirectory = this.BaseDirectory
- member this.Includes = this.Includes
- member this.Excludes = this.Excludes
-
- interface IEnumerable with
-
- member this.GetEnumerator() =
- let hashSet = HashSet()
-
- let excludes =
- seq {
- for pattern in this.Excludes do
- yield! Glob.search this.BaseDirectory pattern
- }
- |> Set.ofSeq
-
- let files =
- seq {
- for pattern in this.Includes do
- yield! Glob.search this.BaseDirectory pattern
- }
- |> Seq.filter (fun x -> not (Set.contains x excludes))
- |> Seq.filter (fun x -> hashSet.Add x)
-
- files.GetEnumerator()
-
- member this.GetEnumerator() =
- (this :> IEnumerable).GetEnumerator()
- :> System.Collections.IEnumerator
-
- type ResolvedGlobbingPattern =
- {
- BaseDirectory: string
- Includes: string list
- Excludes: string list
- Results: string list
- }
-
- interface IGlobbingPattern with
- member this.BaseDirectory = this.BaseDirectory
- member this.Includes = this.Includes
- member this.Excludes = this.Excludes
-
- interface IEnumerable with
- member this.GetEnumerator() =
- (this.Results :> IEnumerable).GetEnumerator()
-
- member this.GetEnumerator() =
- (this :> IEnumerable).GetEnumerator()
- :> System.Collections.IEnumerator
-
- []
- module GlobbingPatternExtensions =
- type IGlobbingPattern with
-
- member internal this.Pattern =
- match this with
- | :? LazyGlobbingPattern as l -> l
- | _ ->
- {
- BaseDirectory = this.BaseDirectory
- Includes = this.Includes
- Excludes = this.Excludes
- }
-
- member this.Resolve() =
- match this with
- | :? ResolvedGlobbingPattern as res -> res :> IGlobbingPattern
- | _ ->
- let list = this |> Seq.toList
-
- {
- BaseDirectory = this.BaseDirectory
- Includes = this.Includes
- Excludes = this.Excludes
- Results = list
- }
- :> IGlobbingPattern
-
- /// Adds the given pattern to the file includes
- member this.And pattern =
- { this.Pattern with Includes = this.Includes @ [ pattern ] }
- :> IGlobbingPattern
-
- /// Ignores files with the given pattern
- member this.ButNot pattern =
- { this.Pattern with Excludes = pattern :: this.Excludes }
- :> IGlobbingPattern
-
- /// Sets a directory as BaseDirectory.
- member this.SetBaseDirectory(dir: string) =
- { this.Pattern with
- BaseDirectory = dir.TrimEnd(Path.DirectorySeparatorChar)
- }
- :> IGlobbingPattern
-
- /// Checks if a particular file is matched
- member this.IsMatch(path: string) =
- let fullDir (pattern: string) =
- if Path.IsPathRooted(pattern) then
- pattern
- else
- System.IO.Path.Combine(this.BaseDirectory, pattern)
-
- let fullPath = Path.GetFullPath path
-
- let included =
- this.Includes
- |> List.exists (fun fileInclude ->
- Glob.isMatch (fullDir fileInclude) fullPath
- )
-
- let excluded =
- this.Excludes
- |> List.exists (fun fileExclude ->
- Glob.isMatch (fullDir fileExclude) fullPath
- )
-
- included && not excluded
-
- []
- module GlobbingPattern =
- let private defaultBaseDir = Path.GetFullPath "."
-
- /// Include files
- let create x =
- {
- BaseDirectory = defaultBaseDir
- Includes = [ x ]
- Excludes = []
- }
- :> IGlobbingPattern
-
- /// Start an empty globbing pattern from the specified directory
- let createFrom (dir: string) =
- {
- BaseDirectory = dir
- Includes = []
- Excludes = []
- }
- :> IGlobbingPattern
-
- /// Sets a directory as baseDirectory for fileIncludes.
- let setBaseDir (dir: string) (fileIncludes: IGlobbingPattern) =
- fileIncludes.SetBaseDirectory dir
-
- /// Get base include directories.
- ///
- /// Used to get a smaller set of directories from a globbing pattern.
- let getBaseDirectoryIncludes (fileIncludes: IGlobbingPattern) =
- let directoryIncludes =
- fileIncludes.Includes
- |> Seq.map (fun file ->
- Glob.getRoot fileIncludes.BaseDirectory file
- )
-
- // remove subdirectories
- directoryIncludes
- |> Seq.filter (fun d ->
- directoryIncludes
- |> Seq.exists (fun p ->
- d.StartsWith(
- p + string Path.DirectorySeparatorChar,
- StringComparison.Ordinal
- )
- && p <> d
- )
- |> not
- )
- |> Seq.toList
-
- /// Contains operators to find and process files.
- ///
- /// ### Simple glob using as list
- ///
- /// let csProjectFiles = !! "src/*.csproj"
- ///
- /// for projectFile in csProjectFiles do
- /// printf "F# ProjectFile: %s" projectFile
- ///
- /// ### Combine globs
- ///
- /// let projectFiles =
- /// !! "src/*/*.*proj"
- /// ++ "src/*/*.target"
- /// -- "src/*/*.vbproj"
- ///
- /// for projectFile in projectFiles do
- /// printf "ProjectFile: %s" projectFile
- ///
- module Operators =
- /// Add Include operator
- let inline (++) (x: IGlobbingPattern) pattern = x.And pattern
-
- /// Exclude operator
- let inline (--) (x: IGlobbingPattern) pattern = x.ButNot pattern
-
- /// Includes a single pattern and scans the files - !! x = AllFilesMatching x
- let inline (!!) x = GlobbingPattern.create x
diff --git a/src/Fable.Cli/Main.fs b/src/Fable.Cli/Main.fs
index 20c7ba90ba..fe23dfb95e 100644
--- a/src/Fable.Cli/Main.fs
+++ b/src/Fable.Cli/Main.fs
@@ -12,7 +12,8 @@ open Fable
open Fable.AST
open Fable.Transforms
open Fable.Transforms.State
-open ProjectCracker
+open Fable.Compiler.ProjectCracker
+open Fable.Compiler.Util
module private Util =
type PathResolver with
@@ -122,7 +123,9 @@ module private Util =
let logErrors rootDir (logs: Log seq) =
logs
|> Seq.filter (fun log -> log.Severity = Severity.Error)
- |> Seq.iter (fun log -> Log.error (formatLog rootDir log))
+ |> Seq.iter (fun log ->
+ Fable.Compiler.Util.Log.error (formatLog rootDir log)
+ )
let getFSharpDiagnostics (diagnostics: FSharpDiagnostic array) =
diagnostics
@@ -433,29 +436,12 @@ type FsWatcher(delayMs: int) =
|> Observable.throttle delayMs
|> Observable.map caseInsensitiveSet
-// TODO: Check the path is actually normalized?
-type File(normalizedFullPath: string) =
- let mutable sourceHash = None
- member _.NormalizedFullPath = normalizedFullPath
-
- member _.ReadSource() =
- match sourceHash with
- | Some h -> h, lazy File.readAllTextNonBlocking normalizedFullPath
- | _ ->
- let source = File.readAllTextNonBlocking normalizedFullPath
- let h = hash source
- sourceHash <- Some h
- h, lazy source
-
- static member MakeSourceReader(files: File[]) =
- let fileDic =
- files |> Seq.map (fun f -> f.NormalizedFullPath, f) |> dict
-
- let sourceReader f = fileDic[f].ReadSource()
- files |> Array.map (fun file -> file.NormalizedFullPath), sourceReader
-
type ProjectCracked
- (cliArgs: CliArgs, crackerResponse: CrackerResponse, sourceFiles: File array)
+ (
+ cliArgs: CliArgs,
+ crackerResponse: CrackerResponse,
+ sourceFiles: Fable.Compiler.File array
+ )
=
member _.CliArgs = cliArgs
@@ -532,7 +518,9 @@ OUTPUT TYPE: {result.OutputType}
"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
+ let sourceFiles =
+ result.ProjectOptions.SourceFiles |> Array.map Fable.Compiler.File
+
ProjectCracked(cliArgs, result, sourceFiles)
type FableCompileResult =
@@ -553,7 +541,7 @@ type ReplyChannel =
type FableCompilerMsg =
| GetFableProject of replyChannel: AsyncReplyChannel
| StartCompilation of
- sourceFiles: File[] *
+ sourceFiles: Fable.Compiler.File[] *
filesToCompile: string[] *
pathResolver: PathResolver *
isSilent: bool *
@@ -613,9 +601,9 @@ type FableCompilerState =
and FableCompiler
(
+ checker: InteractiveChecker,
projCracked: ProjectCracked,
- fableProj: Project,
- checker: InteractiveChecker
+ fableProj: Project
)
=
let agent =
@@ -706,7 +694,8 @@ and FableCompiler
FSharpCompilationFinished
(fun () ->
let filePaths, sourceReader =
- File.MakeSourceReader sourceFiles
+ Fable.Compiler.File.MakeSourceReader
+ sourceFiles
let subscriber =
if
@@ -930,12 +919,12 @@ and FableCompiler
getPlugin = loadType projCracked.CliArgs
)
- return FableCompiler(projCracked, fableProj, checker)
+ return FableCompiler(checker, projCracked, fableProj)
}
member _.CompileToFile(outFile: string) =
let filePaths, sourceReader =
- File.MakeSourceReader projCracked.SourceFiles
+ Fable.Compiler.File.MakeSourceReader projCracked.SourceFiles
checker.Compile(filePaths, sourceReader, outFile)
@@ -1049,7 +1038,7 @@ type State =
let private getFilesToCompile
(state: State)
(changes: ISet)
- (oldFiles: IDictionary option)
+ (oldFiles: IDictionary option)
(projCracked: ProjectCracked)
=
let pendingFiles = set state.PendingFiles
@@ -1058,7 +1047,7 @@ let private getFilesToCompile
let projCracked =
projCracked.MapSourceFiles(fun file ->
if changes.Contains(file.NormalizedFullPath) then
- File(file.NormalizedFullPath)
+ Fable.Compiler.File(file.NormalizedFullPath)
else
file
)
diff --git a/src/Fable.Cli/Pipeline.fs b/src/Fable.Cli/Pipeline.fs
index bf2e7355da..78b309a824 100644
--- a/src/Fable.Cli/Pipeline.fs
+++ b/src/Fable.Cli/Pipeline.fs
@@ -4,6 +4,7 @@ open System
open Fable
open Fable.AST
open Fable.Transforms
+open Fable.Compiler.Util
type Stream =
static member WriteToFile(memoryStream: IO.Stream, filePath: string) =
diff --git a/src/Fable.Cli/Printers.fs b/src/Fable.Cli/Printers.fs
index 70db45760c..809320f15b 100644
--- a/src/Fable.Cli/Printers.fs
+++ b/src/Fable.Cli/Printers.fs
@@ -3,6 +3,7 @@ module Fable.Cli.Printers
open System.IO
open FSharp.Compiler.Symbols
open Fable
+open Fable.Compiler.Util
let attribsOfSymbol (s: FSharpSymbol) =
[
diff --git a/src/Fable.Compiler/CHANGELOG.md b/src/Fable.Compiler/CHANGELOG.md
new file mode 100644
index 0000000000..c7ac6df3a0
--- /dev/null
+++ b/src/Fable.Compiler/CHANGELOG.md
@@ -0,0 +1,9 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## Unreleased
+
+* Initial release
diff --git a/src/Fable.Compiler/Fable.Compiler.fsproj b/src/Fable.Compiler/Fable.Compiler.fsproj
new file mode 100644
index 0000000000..53e43832bf
--- /dev/null
+++ b/src/Fable.Compiler/Fable.Compiler.fsproj
@@ -0,0 +1,56 @@
+
+
+
+ net6.0
+ true
+ true
+ true
+ Fable.Compiler
+ 0.1.0
+
+
+
+
+ embedded
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Fable.Compiler/File.fs b/src/Fable.Compiler/File.fs
new file mode 100644
index 0000000000..724a23f819
--- /dev/null
+++ b/src/Fable.Compiler/File.fs
@@ -0,0 +1,41 @@
+namespace Fable.Compiler
+
+open System.IO
+
+// TODO: Check the path is actually normalized?
+type File(normalizedFullPath: string) =
+ let mutable sourceHash = None
+
+ let readAllTextNonBlocking (path: string) =
+ if File.Exists(path) then
+ use fileStream =
+ new FileStream(
+ path,
+ FileMode.Open,
+ FileAccess.Read,
+ FileShare.ReadWrite
+ )
+
+ use textReader = new StreamReader(fileStream)
+ textReader.ReadToEnd()
+ else
+ // Log.always("File does not exist: " + path)
+ ""
+
+ member _.NormalizedFullPath = normalizedFullPath
+
+ member _.ReadSource() =
+ match sourceHash with
+ | Some h -> h, lazy readAllTextNonBlocking normalizedFullPath
+ | _ ->
+ let source = readAllTextNonBlocking normalizedFullPath
+ let h = hash source
+ sourceHash <- Some h
+ h, lazy source
+
+ static member MakeSourceReader(files: File array) =
+ let fileDic =
+ files |> Seq.map (fun f -> f.NormalizedFullPath, f) |> dict
+
+ let sourceReader f = fileDic[f].ReadSource()
+ files |> Array.map (fun file -> file.NormalizedFullPath), sourceReader
diff --git a/src/Fable.Compiler/Globbing.fs b/src/Fable.Compiler/Globbing.fs
new file mode 100644
index 0000000000..c8c5db7bc2
--- /dev/null
+++ b/src/Fable.Compiler/Globbing.fs
@@ -0,0 +1,509 @@
+module Fable.Compiler.Globbing
+
+open System
+open System.Collections.Generic
+open System.IO
+
+/// Globbing support and operators
+///
+/// Forked from `Fake.IO.FileSystem`
+///
+/// This module contains a file pattern globbing implementation.
+[]
+module Glob =
+ open System
+ open System.Text.RegularExpressions
+
+ // Normalizes path for different OS
+ let inline normalizePath (path: string) =
+ path
+ .Replace('\\', Path.DirectorySeparatorChar)
+ .Replace('/', Path.DirectorySeparatorChar)
+
+ type private SearchOption =
+ | Directory of string
+ | Drive of string
+ | Recursive
+ | FilePattern of string
+
+ let private checkSubDirs absolute (dir: string) root =
+ if dir.Contains "*" then
+ try
+ Directory.EnumerateDirectories(
+ root,
+ dir,
+ SearchOption.TopDirectoryOnly
+ )
+ |> Seq.toList
+ with :? System.IO.DirectoryNotFoundException ->
+ List.empty
+ else
+ let path = Path.Combine(root, dir)
+
+ let di =
+ if absolute then
+ new DirectoryInfo(dir)
+ else
+ new DirectoryInfo(path)
+
+ if di.Exists then
+ [ di.FullName ]
+ else
+ []
+
+ let rec private buildPaths acc (input: SearchOption list) =
+ match input with
+ | [] -> acc
+ | Directory name :: t ->
+ let subDirs = List.collect (checkSubDirs false name) acc
+ buildPaths subDirs t
+ | Drive name :: t ->
+ let subDirs = List.collect (checkSubDirs true name) acc
+ buildPaths subDirs t
+ | Recursive :: [] ->
+ let dirs =
+ Seq.collect
+ (fun dir ->
+ try
+ Directory.EnumerateFileSystemEntries(
+ dir,
+ "*",
+ SearchOption.AllDirectories
+ )
+ with :? System.IO.DirectoryNotFoundException ->
+ Seq.empty
+ )
+ acc
+
+ buildPaths (acc @ Seq.toList dirs) []
+ | Recursive :: t ->
+ let dirs =
+ Seq.collect
+ (fun dir ->
+ try
+ Directory.EnumerateDirectories(
+ dir,
+ "*",
+ SearchOption.AllDirectories
+ )
+ with :? System.IO.DirectoryNotFoundException ->
+ Seq.empty
+ )
+ acc
+
+ buildPaths (acc @ Seq.toList dirs) t
+ | FilePattern pattern :: _ ->
+ acc
+ |> List.collect (fun dir ->
+ if Directory.Exists(Path.Combine(dir, pattern)) then
+ [ Path.Combine(dir, pattern) ]
+ else
+ try
+ Directory.EnumerateFiles(dir, pattern) |> Seq.toList
+ with
+ | :? System.IO.DirectoryNotFoundException
+ | :? System.IO.PathTooLongException -> []
+ )
+
+ let private driveRegex = Regex(@"^[A-Za-z]:$", RegexOptions.Compiled)
+
+ let inline private normalizeOutputPath (p: string) =
+ p
+ .Replace('\\', Path.DirectorySeparatorChar)
+ .Replace('/', Path.DirectorySeparatorChar)
+ .TrimEnd(Path.DirectorySeparatorChar)
+
+ let internal getRoot (baseDirectory: string) (pattern: string) =
+ let baseDirectory = normalizePath baseDirectory
+ let normPattern = normalizePath pattern
+
+ let patternParts =
+ normPattern.Split(
+ [|
+ '/'
+ '\\'
+ |],
+ StringSplitOptions.RemoveEmptyEntries
+ )
+
+ let patternPathParts =
+ patternParts
+ |> Seq.takeWhile (fun p -> not (p.Contains("*")))
+ |> Seq.toArray
+
+ let globRoot =
+ // If we did not find any "*", then drop the last bit (it is a file name, not a pattern)
+ (if patternPathParts.Length = patternParts.Length then
+ patternPathParts.[0 .. patternPathParts.Length - 2]
+ else
+ patternPathParts)
+ |> String.concat (Path.DirectorySeparatorChar.ToString())
+
+ let globRoot =
+ // If we dropped "/" from the beginning of the path in the 'Split' call, put it back!
+ if normPattern.StartsWith('/') then
+ "/" + globRoot
+ else
+ globRoot
+
+ if Path.IsPathRooted globRoot then
+ globRoot
+ else
+ Path.Combine(baseDirectory, globRoot)
+
+ let internal search (baseDir: string) (originalInput: string) =
+ let baseDir = normalizePath baseDir
+ let input = normalizePath originalInput
+
+ let input =
+ if String.IsNullOrEmpty baseDir then
+ input
+ else
+ // The final \ (or /) makes sure to only match complete folder
+ // names (as one folder name could be a substring of the other)
+ let start =
+ baseDir.TrimEnd([| Path.DirectorySeparatorChar |])
+ + string Path.DirectorySeparatorChar
+ // See https://github.com/fsharp/FAKE/issues/1925
+ if input.StartsWith(start, StringComparison.Ordinal) then
+ input.Substring start.Length
+ else
+ input
+
+ let filePattern = Path.GetFileName(input)
+
+ let splits =
+ input.Split(
+ [|
+ '/'
+ '\\'
+ |],
+ StringSplitOptions.None
+ )
+
+ let baseItems =
+ let start, rest =
+ if
+ input.StartsWith("\\\\", StringComparison.Ordinal)
+ && splits.Length >= 4
+ then
+ let serverName = splits.[2]
+ let share = splits.[3]
+
+ [ Directory(sprintf "\\\\%s\\%s" serverName share) ],
+ splits |> Seq.skip 4
+ elif
+ splits.Length >= 2
+ && Path.IsPathRooted input
+ && driveRegex.IsMatch splits.[0]
+ then
+ [ Directory(splits.[0] + "\\") ], splits |> Seq.skip 1
+ elif
+ splits.Length >= 2
+ && Path.IsPathRooted input
+ && input.StartsWith '/'
+ then
+ [ Directory("/") ], splits |> Array.toSeq
+ else
+ if Path.IsPathRooted input then
+ if input.StartsWith '\\' then
+ failwithf
+ "Please remove the leading '\\' or '/' and replace them with \
+ '.\\' or './' if you want to use a relative path. Leading \
+ slashes are considered an absolute path (input was '%s')!"
+ originalInput
+ else
+ failwithf
+ "Unknown globbing input '%s', try to use a \
+ relative path and report an issue!"
+ originalInput
+
+ [], splits |> Array.toSeq
+
+ let restList =
+ rest
+ |> Seq.filter (String.IsNullOrEmpty >> not)
+ |> Seq.map (
+ function
+ | "**" -> Recursive
+ | a when a = filePattern -> FilePattern(a)
+ | a -> Directory(a)
+ )
+ |> Seq.toList
+
+ start @ restList
+
+ baseItems |> buildPaths [ baseDir ] |> List.map normalizeOutputPath
+
+ let internal compileGlobToRegex pattern =
+ let pattern = normalizePath pattern
+
+ let escapedPattern = (Regex.Escape pattern)
+
+ let regexPattern =
+ let xTOy =
+ [
+ "dirwildcard", (@"\\\*\\\*(/|\\\\)", @"(.*(/|\\))?")
+ "stardotstar", (@"\\\*\\.\\\*", @"([^\\/]*)")
+ "wildcard", (@"\\\*", @"([^\\/]*)")
+ ]
+ |> List.map (fun (key, (pattern, replace)) ->
+ let pattern = sprintf "(?<%s>%s)" key pattern
+ key, (pattern, replace)
+ )
+
+ let xTOyMap = xTOy |> Map.ofList
+
+ let replacePattern =
+ xTOy
+ |> List.map (fun x -> x |> snd |> fst)
+ |> String.concat ("|")
+
+ let replaced =
+ Regex(replacePattern)
+ .Replace(
+ escapedPattern,
+ fun m ->
+ let matched =
+ xTOy
+ |> Seq.map (fst)
+ |> Seq.find (fun n -> m.Groups.Item(n).Success)
+
+ (xTOyMap |> Map.tryFind matched).Value |> snd
+ )
+
+ "^" + replaced + "$"
+
+ Regex(regexPattern)
+
+ let private globRegexCache =
+ System.Collections.Concurrent.ConcurrentDictionary()
+
+ let isMatch pattern path : bool =
+ let path = normalizePath path
+
+ let regex =
+ let outRegex: ref = ref null
+
+ if globRegexCache.TryGetValue(pattern, outRegex) then
+ outRegex.Value
+ else
+ let compiled = compileGlobToRegex pattern
+ globRegexCache.TryAdd(pattern, compiled) |> ignore
+ compiled
+
+ regex.IsMatch(path)
+
+type IGlobbingPattern =
+ inherit IEnumerable
+ abstract BaseDirectory: string
+ abstract Includes: string list
+ abstract Excludes: string list
+
+type LazyGlobbingPattern =
+ {
+ BaseDirectory: string
+ Includes: string list
+ Excludes: string list
+ }
+
+ interface IGlobbingPattern with
+ member this.BaseDirectory = this.BaseDirectory
+ member this.Includes = this.Includes
+ member this.Excludes = this.Excludes
+
+ interface IEnumerable with
+
+ member this.GetEnumerator() =
+ let hashSet = HashSet()
+
+ let excludes =
+ seq {
+ for pattern in this.Excludes do
+ yield! Glob.search this.BaseDirectory pattern
+ }
+ |> Set.ofSeq
+
+ let files =
+ seq {
+ for pattern in this.Includes do
+ yield! Glob.search this.BaseDirectory pattern
+ }
+ |> Seq.filter (fun x -> not (Set.contains x excludes))
+ |> Seq.filter (fun x -> hashSet.Add x)
+
+ files.GetEnumerator()
+
+ member this.GetEnumerator() =
+ (this :> IEnumerable).GetEnumerator()
+ :> System.Collections.IEnumerator
+
+type ResolvedGlobbingPattern =
+ {
+ BaseDirectory: string
+ Includes: string list
+ Excludes: string list
+ Results: string list
+ }
+
+ interface IGlobbingPattern with
+ member this.BaseDirectory = this.BaseDirectory
+ member this.Includes = this.Includes
+ member this.Excludes = this.Excludes
+
+ interface IEnumerable with
+ member this.GetEnumerator() =
+ (this.Results :> IEnumerable).GetEnumerator()
+
+ member this.GetEnumerator() =
+ (this :> IEnumerable).GetEnumerator()
+ :> System.Collections.IEnumerator
+
+[]
+module GlobbingPatternExtensions =
+ type IGlobbingPattern with
+
+ member internal this.Pattern =
+ match this with
+ | :? LazyGlobbingPattern as l -> l
+ | _ ->
+ {
+ BaseDirectory = this.BaseDirectory
+ Includes = this.Includes
+ Excludes = this.Excludes
+ }
+
+ member this.Resolve() =
+ match this with
+ | :? ResolvedGlobbingPattern as res -> res :> IGlobbingPattern
+ | _ ->
+ let list = this |> Seq.toList
+
+ {
+ BaseDirectory = this.BaseDirectory
+ Includes = this.Includes
+ Excludes = this.Excludes
+ Results = list
+ }
+ :> IGlobbingPattern
+
+ /// Adds the given pattern to the file includes
+ member this.And pattern =
+ { this.Pattern with Includes = this.Includes @ [ pattern ] }
+ :> IGlobbingPattern
+
+ /// Ignores files with the given pattern
+ member this.ButNot pattern =
+ { this.Pattern with Excludes = pattern :: this.Excludes }
+ :> IGlobbingPattern
+
+ /// Sets a directory as BaseDirectory.
+ member this.SetBaseDirectory(dir: string) =
+ { this.Pattern with
+ BaseDirectory = dir.TrimEnd(Path.DirectorySeparatorChar)
+ }
+ :> IGlobbingPattern
+
+ /// Checks if a particular file is matched
+ member this.IsMatch(path: string) =
+ let fullDir (pattern: string) =
+ if Path.IsPathRooted(pattern) then
+ pattern
+ else
+ System.IO.Path.Combine(this.BaseDirectory, pattern)
+
+ let fullPath = Path.GetFullPath path
+
+ let included =
+ this.Includes
+ |> List.exists (fun fileInclude ->
+ Glob.isMatch (fullDir fileInclude) fullPath
+ )
+
+ let excluded =
+ this.Excludes
+ |> List.exists (fun fileExclude ->
+ Glob.isMatch (fullDir fileExclude) fullPath
+ )
+
+ included && not excluded
+
+[]
+module GlobbingPattern =
+ let private defaultBaseDir = Path.GetFullPath "."
+
+ /// Include files
+ let create x =
+ {
+ BaseDirectory = defaultBaseDir
+ Includes = [ x ]
+ Excludes = []
+ }
+ :> IGlobbingPattern
+
+ /// Start an empty globbing pattern from the specified directory
+ let createFrom (dir: string) =
+ {
+ BaseDirectory = dir
+ Includes = []
+ Excludes = []
+ }
+ :> IGlobbingPattern
+
+ /// Sets a directory as baseDirectory for fileIncludes.
+ let setBaseDir (dir: string) (fileIncludes: IGlobbingPattern) =
+ fileIncludes.SetBaseDirectory dir
+
+ /// Get base include directories.
+ ///
+ /// Used to get a smaller set of directories from a globbing pattern.
+ let getBaseDirectoryIncludes (fileIncludes: IGlobbingPattern) =
+ let directoryIncludes =
+ fileIncludes.Includes
+ |> Seq.map (fun file ->
+ Glob.getRoot fileIncludes.BaseDirectory file
+ )
+
+ // remove subdirectories
+ directoryIncludes
+ |> Seq.filter (fun d ->
+ directoryIncludes
+ |> Seq.exists (fun p ->
+ d.StartsWith(
+ p + string Path.DirectorySeparatorChar,
+ StringComparison.Ordinal
+ )
+ && p <> d
+ )
+ |> not
+ )
+ |> Seq.toList
+
+/// Contains operators to find and process files.
+///
+/// ### Simple glob using as list
+///
+/// let csProjectFiles = !! "src/*.csproj"
+///
+/// for projectFile in csProjectFiles do
+/// printf "F# ProjectFile: %s" projectFile
+///
+/// ### Combine globs
+///
+/// let projectFiles =
+/// !! "src/*/*.*proj"
+/// ++ "src/*/*.target"
+/// -- "src/*/*.vbproj"
+///
+/// for projectFile in projectFiles do
+/// printf "ProjectFile: %s" projectFile
+///
+module Operators =
+ /// Add Include operator
+ let inline (++) (x: IGlobbingPattern) pattern = x.And pattern
+
+ /// Exclude operator
+ let inline (--) (x: IGlobbingPattern) pattern = x.ButNot pattern
+
+ /// Includes a single pattern and scans the files - !! x = AllFilesMatching x
+ let inline (!!) x = GlobbingPattern.create x
diff --git a/src/Fable.Compiler/Globbing.fsi b/src/Fable.Compiler/Globbing.fsi
new file mode 100644
index 0000000000..4bae9ad036
--- /dev/null
+++ b/src/Fable.Compiler/Globbing.fsi
@@ -0,0 +1,112 @@
+module Fable.Compiler.Globbing
+
+open System.Collections.Generic
+open System.IO
+
+/// Globbing support and operators
+///
+/// Forked from `Fake.IO.FileSystem`
+///
+/// This module contains a file pattern globbing implementation.
+[]
+module Glob =
+ open System
+ open System.Text.RegularExpressions
+
+ val inline normalizePath: path: string -> string
+
+ type private SearchOption =
+ | Directory of string
+ | Drive of string
+ | Recursive
+ | FilePattern of string
+
+ val internal getRoot: baseDirectory: string -> pattern: string -> string
+ val internal search: baseDir: string -> originalInput: string -> string list
+ val internal compileGlobToRegex: pattern: string -> Regex
+ val isMatch: pattern: string -> path: string -> bool
+
+type IGlobbingPattern =
+ inherit IEnumerable
+ abstract BaseDirectory: string
+ abstract Includes: string list
+ abstract Excludes: string list
+
+type LazyGlobbingPattern =
+ {
+ BaseDirectory: string
+ Includes: string list
+ Excludes: string list
+ }
+
+ interface IGlobbingPattern
+ interface IEnumerable
+
+type ResolvedGlobbingPattern =
+ {
+ BaseDirectory: string
+ Includes: string list
+ Excludes: string list
+ Results: string list
+ }
+
+ interface IGlobbingPattern
+ interface IEnumerable
+
+[]
+module GlobbingPatternExtensions =
+ type IGlobbingPattern with
+
+ member internal Pattern: LazyGlobbingPattern
+ member Resolve: unit -> IGlobbingPattern
+ /// Adds the given pattern to the file includes
+ member And: pattern: string -> IGlobbingPattern
+ /// Ignores files with the given pattern
+ member ButNot: pattern: string -> IGlobbingPattern
+ /// Sets a directory as BaseDirectory.
+ member SetBaseDirectory: dir: string -> IGlobbingPattern
+ /// Checks if a particular file is matched
+ member IsMatch: path: string -> bool
+
+[]
+module GlobbingPattern =
+ /// Include files
+ val create: x: string -> IGlobbingPattern
+ /// Start an empty globbing pattern from the specified directory
+ val createFrom: dir: string -> IGlobbingPattern
+
+ /// Sets a directory as baseDirectory for fileIncludes.
+ val setBaseDir:
+ dir: string -> fileIncludes: IGlobbingPattern -> IGlobbingPattern
+
+ /// Get base include directories.
+ ///
+ /// Used to get a smaller set of directories from a globbing pattern.
+ val getBaseDirectoryIncludes: fileIncludes: IGlobbingPattern -> string list
+
+/// Contains operators to find and process files.
+///
+/// ### Simple glob using as list
+///
+/// let csProjectFiles = !! "src/*.csproj"
+///
+/// for projectFile in csProjectFiles do
+/// printf "F# ProjectFile: %s" projectFile
+///
+/// ### Combine globs
+///
+/// let projectFiles =
+/// !! "src/*/*.*proj"
+/// ++ "src/*/*.target"
+/// -- "src/*/*.vbproj"
+///
+/// for projectFile in projectFiles do
+/// printf "ProjectFile: %s" projectFile
+///
+module Operators =
+ /// Add Include operator
+ val inline (++): x: IGlobbingPattern -> pattern: string -> IGlobbingPattern
+ /// Exclude operator
+ val inline (--): x: IGlobbingPattern -> pattern: string -> IGlobbingPattern
+ /// Includes a single pattern and scans the files - !! x = AllFilesMatching x
+ val inline (!!): x: string -> IGlobbingPattern
diff --git a/src/Fable.Compiler/Library.fs b/src/Fable.Compiler/Library.fs
new file mode 100644
index 0000000000..799003610e
--- /dev/null
+++ b/src/Fable.Compiler/Library.fs
@@ -0,0 +1,271 @@
+module Fable.Compiler.CodeServices
+
+open System
+open System.IO
+open FSharp.Compiler.CodeAnalysis
+open FSharp.Compiler.SourceCodeServices
+open Fable
+open Fable.Compiler.Util
+open Fable.Transforms.State
+open Fable.Transforms
+open Fable.Compiler.ProjectCracker
+
+type BabelWriter
+ (
+ com: Compiler,
+ pathResolver: PathResolver,
+ projectFile: string,
+ sourcePath: string,
+ targetPath: string
+ )
+ =
+ // In imports *.ts extensions have to be converted to *.js extensions instead
+ // TODO: incomplete
+ let fileExt = ".js"
+ let sourceDir = Path.GetDirectoryName(sourcePath)
+ let targetDir = Path.GetDirectoryName(targetPath)
+ let memoryStream = new MemoryStream()
+ let streamWriter = new StreamWriter(memoryStream)
+ do streamWriter.NewLine <- "\n"
+
+ // let mapGenerator = lazy (SourceMapSharp.SourceMapGenerator(?sourceRoot = cliArgs.SourceMapsRoot))
+
+ member x.ReadContentAsString() : Async =
+ async {
+ do! streamWriter.FlushAsync() |> Async.AwaitTask
+ memoryStream.Position <- 0L
+ let streamReader = new StreamReader(memoryStream)
+ return! (streamReader.ReadToEndAsync() |> Async.AwaitTask)
+ }
+
+ interface Printer.Writer with
+ // Don't dispose the stream here because we need to access the memory stream to check if file has changed
+ member _.Dispose() = ()
+
+ member _.Write(str) =
+ streamWriter.WriteAsync(str) |> Async.AwaitTask
+
+ member _.MakeImportPath(path) =
+ let projDir = Path.GetDirectoryName(projectFile)
+
+ let path =
+ // TODO: Check precompiled out path for other languages too
+ match pathResolver.TryPrecompiledOutPath(sourceDir, path) with
+ | Some path -> Imports.getRelativePath sourceDir path
+ | None -> path
+
+ // TODO: used to be cliArgs.outDir, could be wrong.
+ let path =
+ Imports.getImportPath
+ pathResolver
+ sourcePath
+ targetPath
+ projDir
+ (Some targetDir)
+ path
+
+ if path.EndsWith(".fs", StringComparison.Ordinal) then
+ let isInFableModules =
+ Path.Combine(targetDir, path) |> Naming.isInFableModules
+
+ File.changeExtensionButUseDefaultExtensionInFableModules
+ JavaScript
+ isInFableModules
+ path
+ fileExt
+ else
+ path
+
+ member _.AddLog(msg, severity, ?range) =
+ com.AddLog(
+ msg,
+ severity,
+ ?range = range,
+ fileName = com.CurrentFile
+ )
+
+ member _.AddSourceMapping
+ (
+ srcLine,
+ srcCol,
+ genLine,
+ genCol,
+ file,
+ displayName
+ )
+ =
+ //
+ ()
+// if cliArgs.SourceMaps then
+// let generated: SourceMapSharp.Util.MappingIndex = { line = genLine; column = genCol }
+// let original: SourceMapSharp.Util.MappingIndex = { line = srcLine; column = srcCol }
+// let targetPath = Path.normalizeFullPath targetPath
+// let sourcePath = defaultArg file sourcePath |> Path.getRelativeFileOrDirPath false targetPath false
+// mapGenerator.Force().AddMapping(generated, original, source=sourcePath, ?name=displayName)
+
+let compileFileToJs
+ (com: Compiler)
+ (pathResolver: PathResolver)
+ (outPath: string)
+ : Async
+ =
+ async {
+ let babel =
+ FSharp2Fable.Compiler.transformFile com
+ |> FableTransforms.transformFile com
+ |> Fable2Babel.Compiler.transformFile com
+
+ use writer =
+ new BabelWriter(
+ com,
+ pathResolver,
+ com.ProjectFile,
+ com.CurrentFile,
+ outPath
+ )
+
+ do! BabelPrinter.run writer babel
+ let! output = writer.ReadContentAsString()
+ return output
+ }
+
+let compileProjectToJavaScript
+ (sourceReader: SourceReader)
+ (checker: InteractiveChecker)
+ (pathResolver: PathResolver)
+ (cliArgs: CliArgs)
+ (crackerResponse: CrackerResponse)
+ : Async