-
Notifications
You must be signed in to change notification settings - Fork 300
/
BabelPrinter.fs
112 lines (87 loc) · 3.03 KB
/
BabelPrinter.fs
1
2
3
4
5
6
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
module Fable.Transforms.BabelPrinter
open System
open Fable
open Fable.AST.Babel
type SourceMapGenerator =
abstract AddMapping:
originalLine: int
* originalColumn: int
* generatedLine: int
* generatedColumn: int
* ?name: string
-> unit
type Writer =
inherit IDisposable
abstract EscapeJsStringLiteral: string -> string
abstract Write: string -> Async<unit>
type PrinterImpl(writer: Writer, map: SourceMapGenerator) =
// TODO: We can make this configurable later
let indentSpaces = " "
let builder = Text.StringBuilder()
let mutable indent = 0
let mutable line = 1
let mutable column = 0
let addLoc (loc: SourceLocation option) =
match loc with
| None -> ()
| Some loc ->
map.AddMapping(originalLine = loc.start.line,
originalColumn = loc.start.column,
generatedLine = line,
generatedColumn = column,
?name = loc.identifierName)
member _.Flush(): Async<unit> =
async {
do! writer.Write(builder.ToString())
builder.Clear() |> ignore
}
member _.PrintNewLine() =
builder.AppendLine() |> ignore
line <- line + 1
column <- 0
interface IDisposable with
member _.Dispose() = writer.Dispose()
interface Printer with
member _.Line = line
member _.Column = column
member _.PushIndentation() =
indent <- indent + 1
member _.PopIndentation() =
if indent > 0 then indent <- indent - 1
member _.AddLocation(loc) =
addLoc loc
member _.Print(str, loc) =
addLoc loc
if column = 0 then
let indent = String.replicate indent indentSpaces
builder.Append(indent) |> ignore
column <- indent.Length
builder.Append(str) |> ignore
column <- column + str.Length
member this.PrintNewLine() =
this.PrintNewLine()
member this.EscapeJsStringLiteral(str) =
writer.EscapeJsStringLiteral(str)
let run writer map (program: Program): Async<unit> =
let printDeclWithExtraLine extraLine (printer: Printer) (decl: ModuleDeclaration) =
decl.Print(printer)
if printer.Column > 0 then
printer.Print(";")
printer.PrintNewLine()
if extraLine then
printer.PrintNewLine()
async {
use printer = new PrinterImpl(writer, map)
let imports, restDecls =
program.Body |> Array.splitWhile (function
| :? ImportDeclaration -> true
| _ -> false)
for decl in imports do
printDeclWithExtraLine false printer decl
printer.PrintNewLine()
do! printer.Flush()
for decl in restDecls do
printDeclWithExtraLine true printer decl
// TODO: Only flush every XXX lines?
do! printer.Flush()
}