Skip to content

Commit bd97580

Browse files
committed
feat: improve detection of StandardLibrary types like Promise, Boolean and add supports for RegExp via a type alias
[converter][web]
1 parent cc99bab commit bd97580

22 files changed

+152
-76
lines changed

src/Glutinum.Converter/Generate.fs

+1-9
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,6 @@ let generateBindingFile (filePath: string) =
4343
for reporter in transformResult.Errors do
4444
Log.error reporter
4545

46-
let outFile =
47-
{
48-
Name = "Glutinum"
49-
Opens = [ "Fable.Core"; "Fable.Core.JsInterop"; "System" ]
50-
}
51-
52-
Printer.printOutFile printer outFile
53-
54-
Printer.print printer transformResult.FSharpAST
46+
Printer.printFile printer transformResult
5547

5648
printer.ToString()

src/Glutinum.Converter/GlueAST.fs

+7
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,13 @@ type GlueTypeReference =
229229
Name: string
230230
FullName: string
231231
TypeArguments: GlueType list
232+
// Should we replace that with a real computation of the FullName
233+
// and use it to determine if it's from standard library?
234+
// I think right now, we don't have a correct FullName because I didn't know how to get it
235+
// but a few days ago, I found a way to access the source file information
236+
// this is how the isStandardLibrary is determined
237+
// so we can perhaps revisit the FullName reader logic with this new knowledge
238+
IsStandardLibrary: bool
232239
}
233240

234241
type GlueTypeUnion = GlueTypeUnion of GlueType list

src/Glutinum.Converter/Printer.fs

+28-17
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,6 @@ type Printer() =
3939

4040
member __.ToStringWithoutTrailNewLine() = buffer.ToString().Trim()
4141

42-
let printOutFile (printer: Printer) (outFile: FSharpOutFile) =
43-
printer.Write($"module rec {outFile.Name}")
44-
printer.NewLine
45-
printer.NewLine
46-
47-
outFile.Opens
48-
|> List.iter (fun o ->
49-
printer.Write($"open {o}")
50-
printer.NewLine
51-
)
52-
5342
module Naming =
5443
let (|Digit|_|) (digit: string) =
5544
if String.IsNullOrWhiteSpace digit then
@@ -280,18 +269,15 @@ and printType (fsharpType: FSharpType) =
280269
| FSharpPrimitive.Number -> "float"
281270
| FSharpPrimitive.Null -> "obj"
282271
| FSharpType.TypeReference typeReference ->
283-
let replacedName =
284-
Naming.mapTypeNameToFableCoreAwareName typeReference.Name
285-
286272
if typeReference.TypeArguments.Length > 0 then
287273
let typeArguments =
288274
typeReference.TypeArguments
289275
|> List.map printType
290276
|> String.concat ", "
291277

292-
$"{replacedName}<{typeArguments}>"
278+
$"{typeReference.Name}<{typeArguments}>"
293279
else
294-
replacedName
280+
typeReference.Name
295281

296282
| FSharpType.TypeParameter name -> $"'{name}"
297283
| FSharpType.Option optionType -> printType optionType + " option"
@@ -880,7 +866,7 @@ let private printTypeAlias (printer: Printer) (aliasInfo: FSharpTypeAlias) =
880866
printer.NewLine
881867
printer.Unindent
882868

883-
let rec print (printer: Printer) (fsharpTypes: FSharpType list) =
869+
let rec private print (printer: Printer) (fsharpTypes: FSharpType list) =
884870
match fsharpTypes with
885871
| fsharpType :: tail ->
886872
printer.NewLine
@@ -957,3 +943,28 @@ let rec print (printer: Printer) (fsharpTypes: FSharpType list) =
957943
print printer tail
958944

959945
| [] -> ()
946+
947+
let printFile (printer: Printer) (transformResult: Transform.TransformResult) =
948+
949+
let outFile =
950+
{
951+
Name = "Glutinum"
952+
Opens = [ "Fable.Core"; "Fable.Core.JsInterop"; "System" ]
953+
}
954+
955+
printer.Write($"module rec {outFile.Name}")
956+
printer.NewLine
957+
printer.NewLine
958+
959+
outFile.Opens
960+
|> List.iter (fun o ->
961+
printer.Write($"open {o}")
962+
printer.NewLine
963+
)
964+
965+
if transformResult.IncludeRegExpAlias then
966+
printer.NewLine
967+
printer.Write "type RegExp = Text.RegularExpressions.Regex"
968+
printer.NewLine
969+
970+
print printer transformResult.FSharpAST

src/Glutinum.Converter/Reader/TypeNode.fs

+5-3
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ let readTypeNode
170170

171171
let symbolOpt = checker.getSymbolAtLocation !!typeReferenceNode.typeName
172172

173-
let readTypeReference () =
173+
let readTypeReference (isStandardLibrary: bool) =
174174
match symbolOpt.Value.flags with
175175
| HasSymbolFlags Ts.SymbolFlags.TypeParameter ->
176176
symbolOpt.Value.name |> GlueType.TypeParameter
@@ -182,6 +182,7 @@ let readTypeNode
182182
checker
183183
(!!typeReferenceNode.typeName)
184184
TypeArguments = readTypeArguments reader typeReferenceNode
185+
IsStandardLibrary = isStandardLibrary
185186
})
186187
|> GlueType.TypeReference
187188

@@ -190,9 +191,9 @@ let readTypeNode
190191
| "Exclude" -> UtilityType.readExclude reader typeReferenceNode
191192
| "Partial" -> UtilityType.readPartial reader typeReferenceNode
192193
| "Record" -> UtilityType.readRecord reader typeReferenceNode
193-
| _ -> readTypeReference ()
194+
| _ -> readTypeReference true
194195
else
195-
readTypeReference ()
196+
readTypeReference false
196197

197198
| Ts.SyntaxKind.ArrayType ->
198199
let arrayTypeNode = typeNode :?> Ts.ArrayTypeNode
@@ -362,6 +363,7 @@ let readTypeNode
362363
Name = expression.expression.getText () // Keep the double expression !!!
363364
FullName = getFullNameOrEmpty checker expression
364365
TypeArguments = readTypeArguments reader expression
366+
IsStandardLibrary = false // TODO: Should we check if it's from the standard library?
365367
})
366368
|> GlueType.TypeReference
367369

src/Glutinum.Converter/Reader/UnionTypeNode.fs

+1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ let rec private readUnionTypeCases
8686
Name = typeReferenceNode.getText ()
8787
FullName = fullName
8888
TypeArguments = []
89+
IsStandardLibrary = isFromEs5Lib symbolOpt
8990
})
9091
|> GlueType.TypeReference
9192
|> List.singleton

src/Glutinum.Converter/Transform.fs

+50-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ type Reporter() =
1313

1414
member val Errors = errors
1515

16+
member val HasRegEpx = false with get, set
17+
1618
// Not really proud of this implementation, but I was not able to make it in a
1719
// pure functional way, using a Tree structure or something similar
1820
// It seems like for now this implementation does the job which is the most important
@@ -43,6 +45,15 @@ type TransformContext
4345
// You should not use this directly, but instead use the AddWarning and AddError methods
4446
member val _Reporter = reporter
4547

48+
member _.ExposeRegExp() =
49+
// TODO: Rework how we memorize if need to expose RegExp alias
50+
// Perhaps, before the printer phase we should traverse the whole AST to find information
51+
// like aliases that we need to expose
52+
// We could propagate the IsStandardLibrary flag to the F# AST to check such information
53+
// Example: If we find an F# TypeReference with the name "RegExp" and the IsStandardLibrary flag is true
54+
// then we need to expose the RegExp alias
55+
reporter.HasRegEpx <- true
56+
4657
member _.ExposeType(typ: FSharpType) =
4758
match parent with
4859
| None -> types.Add(typ)
@@ -99,6 +110,26 @@ type TransformContext
99110

100111
member _.AddError(error: string) = reporter.Errors.Add error
101112

113+
let private mapTypeNameToFableCoreAwareName
114+
(context: TransformContext)
115+
(typeReference: GlueTypeReference)
116+
=
117+
118+
if typeReference.IsStandardLibrary then
119+
match typeReference.Name with
120+
| "Date" -> "JS.Date"
121+
| "Promise" -> "JS.Promise"
122+
| "Uint8Array" -> "JS.Uint8Array"
123+
| "ReadonlyArray" -> "ResizeArray"
124+
| "Array" -> "ResizeArray"
125+
| "Boolean" -> "bool"
126+
| "RegExp" ->
127+
context.ExposeRegExp()
128+
"RegExp"
129+
| name -> name
130+
else
131+
typeReference.Name
132+
102133
let private unwrapOptionIfAlreadyOptional
103134
(context: TransformContext)
104135
(typ: GlueType)
@@ -373,11 +404,15 @@ let rec private transformType
373404

374405
| GlueType.TypeReference typeReference ->
375406
({
376-
Name = Naming.mapTypeNameToFableCoreAwareName typeReference.Name
407+
Name = mapTypeNameToFableCoreAwareName context typeReference
377408
FullName = typeReference.FullName
378409
TypeArguments =
379410
typeReference.TypeArguments |> List.map (transformType context)
380411
Type = //transformType context typeReference.TypeRef
412+
// TODO: This code looks suspicious
413+
// Why would a typeReference always be a string? I think I added that here to make
414+
// the compiler happy because we don't have a concrete type for the TypeReference
415+
// this is because of the recursive types which creates infinite loops in the reader
381416
FSharpType.Primitive FSharpPrimitive.String
382417
}
383418
: FSharpTypeReference)
@@ -1827,7 +1862,8 @@ let private transformTypeAliasDeclaration
18271862
|> FSharpType.TypeAlias
18281863

18291864
| GlueType.TypeReference typeReference ->
1830-
let context = context.PushScope typeReference.Name
1865+
let mappedName = mapTypeNameToFableCoreAwareName context typeReference
1866+
let context = context.PushScope mappedName
18311867

18321868
let handleDefaultCase () =
18331869
({
@@ -1884,7 +1920,7 @@ let private transformTypeAliasDeclaration
18841920
Name = typeAliasName
18851921
Type =
18861922
{
1887-
Name = typeReference.Name
1923+
Name = mappedName
18881924
FullName = typeReference.FullName
18891925
TypeArguments =
18901926
[ FSharpType.Interface typeArgument ]
@@ -2197,11 +2233,20 @@ let private transform
21972233
yield! rootTransformContext.ToList()
21982234
]
21992235

2236+
type TransformResult =
2237+
{
2238+
FSharpAST: FSharpType list
2239+
Warnings: ResizeArray<string>
2240+
Errors: ResizeArray<string>
2241+
IncludeRegExpAlias: bool
2242+
}
2243+
22002244
let apply (glueAst: GlueType list) =
22012245
let reporter = Reporter()
22022246

2203-
{|
2247+
{
22042248
FSharpAST = transform reporter true glueAst
22052249
Warnings = reporter.Warnings
22062250
Errors = reporter.Errors
2207-
|}
2251+
IncludeRegExpAlias = reporter.HasRegEpx
2252+
}

src/Glutinum.Converter/Utils/Naming.fs

-10
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,6 @@ let private escapeName (name: string) : string =
2020
else
2121
name
2222

23-
let mapTypeNameToFableCoreAwareName (name: string) : string =
24-
match name with
25-
| "Date" -> "JS.Date"
26-
| "Promise" -> "JS.Promise"
27-
| "Uint8Array" -> "JS.Uint8Array"
28-
| "ReadonlyArray" -> "ResizeArray"
29-
| "Array" -> "ResizeArray"
30-
| "Boolean" -> "bool"
31-
| name -> name
32-
3323
let removeSurroundingQuotes (text: string) : string =
3424
if String.IsNullOrEmpty text then
3525
""

src/Glutinum.Web/Pages/Editors.FSharpCode.fs

+1-14
Original file line numberDiff line numberDiff line change
@@ -80,20 +80,7 @@ let private generateFile
8080

8181
let transformResult = Transform.apply readerResult.GlueAST
8282

83-
let outFile =
84-
{
85-
Name = "Glutinum"
86-
Opens =
87-
[
88-
"Fable.Core"
89-
"Fable.Core.JsInterop"
90-
"System"
91-
]
92-
}
93-
94-
Printer.printOutFile printer outFile
95-
96-
Printer.print printer transformResult.FSharpAST
83+
Printer.printFile printer transformResult
9784

9885
CompilationResult.Success(
9986
printer.ToString(),

src/Glutinum.Web/Pages/Editors.GlueAST.GlueASTViewer.fs

+3
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,9 @@ type GlueASTViewer =
475475
[
476476
GlueASTViewer.Name typeReference.Name
477477
ASTViewer.renderKeyValue "FullName" typeReference.FullName
478+
ASTViewer.renderKeyValue
479+
"IsStandardLibrary"
480+
(string typeReference.IsStandardLibrary)
478481

479482
typeReference.TypeArguments
480483
|> List.map GlueASTViewer.GlueType

tests/specs/references/intersectionType/insideOfTypeArguments.fsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ type RecordEntryObject =
1111
abstract member n: float with get, set
1212

1313
type RecordEntryArrayItem =
14-
ResizeArray<RecordEntryArrayItem.ReadonlyArray.ReturnType>
14+
ResizeArray<RecordEntryArrayItem.ResizeArray.ReturnType>
1515

1616
module RecordEntryArrayItem =
1717

18-
module ReadonlyArray =
18+
module ResizeArray =
1919

2020
[<AllowNullLiteral>]
2121
[<Interface>]

tests/specs/references/naming/Uint8Array.d.ts

-1
This file was deleted.

tests/specs/references/naming/Uint8Array.fsx

-15
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
type T = Array<number>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module rec Glutinum
2+
3+
open Fable.Core
4+
open Fable.Core.JsInterop
5+
open System
6+
7+
type T =
8+
ResizeArray<float>
9+
10+
(***)
11+
#r "nuget: Fable.Core"
12+
(***)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
type T = Boolean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module rec Glutinum
2+
3+
open Fable.Core
4+
open Fable.Core.JsInterop
5+
open System
6+
7+
type T =
8+
bool
9+
10+
(***)
11+
#r "nuget: Fable.Core"
12+
(***)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
type T = RegExp
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module rec Glutinum
2+
3+
open Fable.Core
4+
open Fable.Core.JsInterop
5+
open System
6+
7+
type RegExp = Text.RegularExpressions.Regex
8+
9+
type T =
10+
RegExp
11+
12+
(***)
13+
#r "nuget: Fable.Core"
14+
(***)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
type T = Uint8Array

0 commit comments

Comments
 (0)